* [PATCH v3 1/9] hw/audio/virtio-sound: remove command and stream mutexes
2026-06-26 12:35 [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support Alexander Mikhalitsyn
@ 2026-06-26 12:35 ` Alexander Mikhalitsyn
2026-06-29 7:43 ` Manos Pitsidianakis
2026-06-26 12:35 ` [PATCH v3 2/9] hw/audio/virtio-sound: allocate an array of streams Alexander Mikhalitsyn
` (8 subsequent siblings)
9 siblings, 1 reply; 26+ messages in thread
From: Alexander Mikhalitsyn @ 2026-06-26 12:35 UTC (permalink / raw)
To: qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
From: Volker Rümelin <vr_qemu@t-online.de>
All code in virtio-snd.c runs with the BQL held. Remove the
command queue mutex and the stream queue mutexes. The qatomic
functions are also not needed.
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
[AM: there were too many conflicts, I did `git checkout --ours -- <.>`
and then reimplemented the patch idea
/AM]
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/audio/virtio-snd.c | 248 +++++++++++++++-------------------
include/hw/audio/virtio-snd.h | 3 -
2 files changed, 110 insertions(+), 141 deletions(-)
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index fb5cff38660..6eb31e2838e 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -19,7 +19,6 @@
#include "qemu/iov.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
-#include "qemu/lockable.h"
#include "system/runstate.h"
#include "trace.h"
#include "qapi/error.h"
@@ -442,7 +441,6 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
stream->id = stream_id;
stream->s = s;
stream->latency_bytes = 0;
- qemu_mutex_init(&stream->queue_mutex);
QSIMPLEQ_INIT(&stream->queue);
/*
@@ -568,9 +566,7 @@ static void virtio_snd_handle_pcm_start_stop(VirtIOSound *s,
stream = virtio_snd_pcm_get_stream(s, stream_id);
if (stream) {
- WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
- stream->active = start;
- }
+ stream->active = start;
if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
audio_be_set_active_out(s->audio_be, stream->voice.out, start);
} else {
@@ -594,10 +590,8 @@ static size_t virtio_snd_pcm_get_io_msgs_count(VirtIOSoundPCMStream *stream)
VirtIOSoundPCMBuffer *buffer, *next;
size_t count = 0;
- WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
- QSIMPLEQ_FOREACH_SAFE(buffer, &stream->queue, entry, next) {
- count += 1;
- }
+ QSIMPLEQ_FOREACH_SAFE(buffer, &stream->queue, entry, next) {
+ count += 1;
}
return count;
}
@@ -739,23 +733,15 @@ static void virtio_snd_process_cmdq(VirtIOSound *s)
{
virtio_snd_ctrl_command *cmd;
- if (unlikely(qatomic_read(&s->processing_cmdq))) {
- return;
- }
-
- WITH_QEMU_LOCK_GUARD(&s->cmdq_mutex) {
- qatomic_set(&s->processing_cmdq, true);
- while (!QTAILQ_EMPTY(&s->cmdq)) {
- cmd = QTAILQ_FIRST(&s->cmdq);
+ while (!QTAILQ_EMPTY(&s->cmdq)) {
+ cmd = QTAILQ_FIRST(&s->cmdq);
- /* process command */
- process_cmd(s, cmd);
+ /* process command */
+ process_cmd(s, cmd);
- QTAILQ_REMOVE(&s->cmdq, cmd, next);
+ QTAILQ_REMOVE(&s->cmdq, cmd, next);
- virtio_snd_ctrl_cmd_free(cmd);
- }
- qatomic_set(&s->processing_cmdq, false);
+ virtio_snd_ctrl_cmd_free(cmd);
}
}
@@ -892,19 +878,17 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
goto tx_err;
}
- WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
- size = iov_size(elem->out_sg, elem->out_num) - msg_sz;
+ size = iov_size(elem->out_sg, elem->out_num) - msg_sz;
- buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
- buffer->elem = elem;
- buffer->populated = false;
- buffer->vq = vq;
- buffer->size = size;
- buffer->offset = 0;
- stream->latency_bytes += size;
+ buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
+ buffer->elem = elem;
+ buffer->populated = false;
+ buffer->vq = vq;
+ buffer->size = size;
+ buffer->offset = 0;
+ stream->latency_bytes += size;
- QSIMPLEQ_INSERT_TAIL(&stream->queue, buffer, entry);
- }
+ QSIMPLEQ_INSERT_TAIL(&stream->queue, buffer, entry);
continue;
tx_err:
@@ -973,16 +957,15 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
if (stream == NULL || stream->info.direction != VIRTIO_SND_D_INPUT) {
goto rx_err;
}
- WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
- size = iov_size(elem->in_sg, elem->in_num) -
- sizeof(virtio_snd_pcm_status);
- buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
- buffer->elem = elem;
- buffer->vq = vq;
- buffer->size = 0;
- buffer->offset = 0;
- QSIMPLEQ_INSERT_TAIL(&stream->queue, buffer, entry);
- }
+
+ size = iov_size(elem->in_sg, elem->in_num) -
+ sizeof(virtio_snd_pcm_status);
+ buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
+ buffer->elem = elem;
+ buffer->vq = vq;
+ buffer->size = 0;
+ buffer->offset = 0;
+ QSIMPLEQ_INSERT_TAIL(&stream->queue, buffer, entry);
continue;
rx_err:
@@ -1086,7 +1069,6 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
virtio_add_queue(vdev, 64, virtio_snd_handle_tx_xfer);
vsnd->queues[VIRTIO_SND_VQ_RX] =
virtio_add_queue(vdev, 64, virtio_snd_handle_rx_xfer);
- qemu_mutex_init(&vsnd->cmdq_mutex);
QTAILQ_INIT(&vsnd->cmdq);
QSIMPLEQ_INIT(&vsnd->invalid);
@@ -1154,52 +1136,50 @@ static void virtio_snd_pcm_out_cb(void *data, int available)
VirtIOSoundPCMBuffer *buffer;
size_t size;
- WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
- while (!QSIMPLEQ_EMPTY(&stream->queue)) {
- buffer = QSIMPLEQ_FIRST(&stream->queue);
- if (!virtio_queue_ready(buffer->vq)) {
- return;
+ while (!QSIMPLEQ_EMPTY(&stream->queue)) {
+ buffer = QSIMPLEQ_FIRST(&stream->queue);
+ if (!virtio_queue_ready(buffer->vq)) {
+ return;
+ }
+ if (!stream->active) {
+ /* Stream has stopped, so do not perform audio_be_write. */
+ return_tx_buffer(stream, buffer);
+ continue;
+ }
+ if (!buffer->populated) {
+ iov_to_buf(buffer->elem->out_sg,
+ buffer->elem->out_num,
+ sizeof(virtio_snd_pcm_xfer),
+ buffer->data,
+ buffer->size);
+ buffer->populated = true;
+ }
+ for (;;) {
+ size = audio_be_write(stream->s->audio_be,
+ stream->voice.out,
+ buffer->data + buffer->offset,
+ MIN(buffer->size, available));
+ assert(size <= MIN(buffer->size, available));
+ if (size == 0) {
+ /* break out of both loops */
+ available = 0;
+ break;
}
- if (!stream->active) {
- /* Stream has stopped, so do not perform audio_be_write. */
+ buffer->size -= size;
+ buffer->offset += size;
+ available -= size;
+ update_latency(stream, size);
+ if (buffer->size < 1) {
return_tx_buffer(stream, buffer);
- continue;
- }
- if (!buffer->populated) {
- iov_to_buf(buffer->elem->out_sg,
- buffer->elem->out_num,
- sizeof(virtio_snd_pcm_xfer),
- buffer->data,
- buffer->size);
- buffer->populated = true;
- }
- for (;;) {
- size = audio_be_write(stream->s->audio_be,
- stream->voice.out,
- buffer->data + buffer->offset,
- MIN(buffer->size, available));
- assert(size <= MIN(buffer->size, available));
- if (size == 0) {
- /* break out of both loops */
- available = 0;
- break;
- }
- buffer->size -= size;
- buffer->offset += size;
- available -= size;
- update_latency(stream, size);
- if (buffer->size < 1) {
- return_tx_buffer(stream, buffer);
- break;
- }
- if (!available) {
- break;
- }
+ break;
}
if (!available) {
break;
}
}
+ if (!available) {
+ break;
+ }
}
}
@@ -1250,55 +1230,53 @@ static void virtio_snd_pcm_in_cb(void *data, int available)
VirtIOSoundPCMBuffer *buffer;
size_t size, max_size, to_read;
- WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
- while (!QSIMPLEQ_EMPTY(&stream->queue)) {
- buffer = QSIMPLEQ_FIRST(&stream->queue);
- if (!virtio_queue_ready(buffer->vq)) {
- return;
- }
- if (!stream->active) {
- /* Stream has stopped, so do not perform audio_be_read. */
- return_rx_buffer(stream, buffer);
- continue;
- }
+ while (!QSIMPLEQ_EMPTY(&stream->queue)) {
+ buffer = QSIMPLEQ_FIRST(&stream->queue);
+ if (!virtio_queue_ready(buffer->vq)) {
+ return;
+ }
+ if (!stream->active) {
+ /* Stream has stopped, so do not perform audio_be_read. */
+ return_rx_buffer(stream, buffer);
+ continue;
+ }
+
+ max_size = iov_size(buffer->elem->in_sg, buffer->elem->in_num);
+ if (max_size <= sizeof(virtio_snd_pcm_status)) {
+ return_rx_buffer(stream, buffer);
+ continue;
+ }
+ max_size -= sizeof(virtio_snd_pcm_status);
- max_size = iov_size(buffer->elem->in_sg, buffer->elem->in_num);
- if (max_size <= sizeof(virtio_snd_pcm_status)) {
+ for (;;) {
+ if (buffer->size >= max_size) {
return_rx_buffer(stream, buffer);
- continue;
+ break;
}
- max_size -= sizeof(virtio_snd_pcm_status);
-
- for (;;) {
- if (buffer->size >= max_size) {
- return_rx_buffer(stream, buffer);
- break;
- }
- to_read = stream->params.period_bytes - buffer->size;
- to_read = MIN(to_read, available);
- to_read = MIN(to_read, max_size - buffer->size);
- size = audio_be_read(stream->s->audio_be,
- stream->voice.in,
- buffer->data + buffer->size,
- to_read);
- if (!size) {
- available = 0;
- break;
- }
- buffer->size += size;
- available -= size;
- if (buffer->size >= stream->params.period_bytes) {
- return_rx_buffer(stream, buffer);
- break;
- }
- if (!available) {
- break;
- }
+ to_read = stream->params.period_bytes - buffer->size;
+ to_read = MIN(to_read, available);
+ to_read = MIN(to_read, max_size - buffer->size);
+ size = audio_be_read(stream->s->audio_be,
+ stream->voice.in,
+ buffer->data + buffer->size,
+ to_read);
+ if (!size) {
+ available = 0;
+ break;
+ }
+ buffer->size += size;
+ available -= size;
+ if (buffer->size >= stream->params.period_bytes) {
+ return_rx_buffer(stream, buffer);
+ break;
}
if (!available) {
break;
}
}
+ if (!available) {
+ break;
+ }
}
}
@@ -1315,11 +1293,9 @@ static inline void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream)
(stream->info.direction == VIRTIO_SND_D_OUTPUT) ? return_tx_buffer :
return_rx_buffer;
- WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
- while (!QSIMPLEQ_EMPTY(&stream->queue)) {
- buffer = QSIMPLEQ_FIRST(&stream->queue);
- cb(stream, buffer);
- }
+ while (!QSIMPLEQ_EMPTY(&stream->queue)) {
+ buffer = QSIMPLEQ_FIRST(&stream->queue);
+ cb(stream, buffer);
}
}
@@ -1338,14 +1314,12 @@ static void virtio_snd_unrealize(DeviceState *dev)
if (stream) {
virtio_snd_process_cmdq(stream->s);
virtio_snd_pcm_close(stream);
- qemu_mutex_destroy(&stream->queue_mutex);
g_free(stream);
}
}
g_free(vsnd->pcm.streams);
}
g_free(vsnd->pcm.pcm_params);
- qemu_mutex_destroy(&vsnd->cmdq_mutex);
virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]);
virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_EVENT]);
virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_TX]);
@@ -1366,12 +1340,10 @@ static void virtio_snd_reset(VirtIODevice *vdev)
*/
g_assert(QSIMPLEQ_EMPTY(&vsnd->invalid));
- WITH_QEMU_LOCK_GUARD(&vsnd->cmdq_mutex) {
- while (!QTAILQ_EMPTY(&vsnd->cmdq)) {
- cmd = QTAILQ_FIRST(&vsnd->cmdq);
- QTAILQ_REMOVE(&vsnd->cmdq, cmd, next);
- virtio_snd_ctrl_cmd_free(cmd);
- }
+ while (!QTAILQ_EMPTY(&vsnd->cmdq)) {
+ cmd = QTAILQ_FIRST(&vsnd->cmdq);
+ QTAILQ_REMOVE(&vsnd->cmdq, cmd, next);
+ virtio_snd_ctrl_cmd_free(cmd);
}
}
diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
index e28f1be5db9..fce7d1feea2 100644
--- a/include/hw/audio/virtio-snd.h
+++ b/include/hw/audio/virtio-snd.h
@@ -146,7 +146,6 @@ struct VirtIOSoundPCMStream {
SWVoiceIn *in;
SWVoiceOut *out;
} voice;
- QemuMutex queue_mutex;
bool active;
uint32_t latency_bytes;
QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) queue;
@@ -218,9 +217,7 @@ struct VirtIOSound {
AudioBackend *audio_be;
VMChangeStateEntry *vmstate;
virtio_snd_config snd_conf;
- QemuMutex cmdq_mutex;
QTAILQ_HEAD(, virtio_snd_ctrl_command) cmdq;
- bool processing_cmdq;
/*
* Convenience queue to keep track of invalid tx/rx queue messages inside
* the tx/rx callbacks.
--
2.47.3
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v3 1/9] hw/audio/virtio-sound: remove command and stream mutexes
2026-06-26 12:35 ` [PATCH v3 1/9] hw/audio/virtio-sound: remove command and stream mutexes Alexander Mikhalitsyn
@ 2026-06-29 7:43 ` Manos Pitsidianakis
0 siblings, 0 replies; 26+ messages in thread
From: Manos Pitsidianakis @ 2026-06-29 7:43 UTC (permalink / raw)
To: Alexander Mikhalitsyn, qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
On Fri, 26 Jun 2026 15:35, Alexander Mikhalitsyn <alexander@mihalicyn.com> wrote:
>From: Volker Rümelin <vr_qemu@t-online.de>
>
>All code in virtio-snd.c runs with the BQL held. Remove the
>command queue mutex and the stream queue mutexes. The qatomic
>functions are also not needed.
>
>Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
>[AM: there were too many conflicts, I did `git checkout --ours -- <.>`
> and then reimplemented the patch idea
>/AM]
>Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
>Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>---
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
> hw/audio/virtio-snd.c | 248 +++++++++++++++-------------------
> include/hw/audio/virtio-snd.h | 3 -
> 2 files changed, 110 insertions(+), 141 deletions(-)
>
>diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
>index fb5cff38660..6eb31e2838e 100644
>--- a/hw/audio/virtio-snd.c
>+++ b/hw/audio/virtio-snd.c
>@@ -19,7 +19,6 @@
> #include "qemu/iov.h"
> #include "qemu/log.h"
> #include "qemu/error-report.h"
>-#include "qemu/lockable.h"
> #include "system/runstate.h"
> #include "trace.h"
> #include "qapi/error.h"
>@@ -442,7 +441,6 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
> stream->id = stream_id;
> stream->s = s;
> stream->latency_bytes = 0;
>- qemu_mutex_init(&stream->queue_mutex);
> QSIMPLEQ_INIT(&stream->queue);
>
> /*
>@@ -568,9 +566,7 @@ static void virtio_snd_handle_pcm_start_stop(VirtIOSound *s,
>
> stream = virtio_snd_pcm_get_stream(s, stream_id);
> if (stream) {
>- WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
>- stream->active = start;
>- }
>+ stream->active = start;
> if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
> audio_be_set_active_out(s->audio_be, stream->voice.out, start);
> } else {
>@@ -594,10 +590,8 @@ static size_t virtio_snd_pcm_get_io_msgs_count(VirtIOSoundPCMStream *stream)
> VirtIOSoundPCMBuffer *buffer, *next;
> size_t count = 0;
>
>- WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
>- QSIMPLEQ_FOREACH_SAFE(buffer, &stream->queue, entry, next) {
>- count += 1;
>- }
>+ QSIMPLEQ_FOREACH_SAFE(buffer, &stream->queue, entry, next) {
>+ count += 1;
> }
> return count;
> }
>@@ -739,23 +733,15 @@ static void virtio_snd_process_cmdq(VirtIOSound *s)
> {
> virtio_snd_ctrl_command *cmd;
>
>- if (unlikely(qatomic_read(&s->processing_cmdq))) {
>- return;
>- }
>-
>- WITH_QEMU_LOCK_GUARD(&s->cmdq_mutex) {
>- qatomic_set(&s->processing_cmdq, true);
>- while (!QTAILQ_EMPTY(&s->cmdq)) {
>- cmd = QTAILQ_FIRST(&s->cmdq);
>+ while (!QTAILQ_EMPTY(&s->cmdq)) {
>+ cmd = QTAILQ_FIRST(&s->cmdq);
>
>- /* process command */
>- process_cmd(s, cmd);
>+ /* process command */
>+ process_cmd(s, cmd);
>
>- QTAILQ_REMOVE(&s->cmdq, cmd, next);
>+ QTAILQ_REMOVE(&s->cmdq, cmd, next);
>
>- virtio_snd_ctrl_cmd_free(cmd);
>- }
>- qatomic_set(&s->processing_cmdq, false);
>+ virtio_snd_ctrl_cmd_free(cmd);
> }
> }
>
>@@ -892,19 +878,17 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
> goto tx_err;
> }
>
>- WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
>- size = iov_size(elem->out_sg, elem->out_num) - msg_sz;
>+ size = iov_size(elem->out_sg, elem->out_num) - msg_sz;
>
>- buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
>- buffer->elem = elem;
>- buffer->populated = false;
>- buffer->vq = vq;
>- buffer->size = size;
>- buffer->offset = 0;
>- stream->latency_bytes += size;
>+ buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
>+ buffer->elem = elem;
>+ buffer->populated = false;
>+ buffer->vq = vq;
>+ buffer->size = size;
>+ buffer->offset = 0;
>+ stream->latency_bytes += size;
>
>- QSIMPLEQ_INSERT_TAIL(&stream->queue, buffer, entry);
>- }
>+ QSIMPLEQ_INSERT_TAIL(&stream->queue, buffer, entry);
> continue;
>
> tx_err:
>@@ -973,16 +957,15 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
> if (stream == NULL || stream->info.direction != VIRTIO_SND_D_INPUT) {
> goto rx_err;
> }
>- WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
>- size = iov_size(elem->in_sg, elem->in_num) -
>- sizeof(virtio_snd_pcm_status);
>- buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
>- buffer->elem = elem;
>- buffer->vq = vq;
>- buffer->size = 0;
>- buffer->offset = 0;
>- QSIMPLEQ_INSERT_TAIL(&stream->queue, buffer, entry);
>- }
>+
>+ size = iov_size(elem->in_sg, elem->in_num) -
>+ sizeof(virtio_snd_pcm_status);
>+ buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
>+ buffer->elem = elem;
>+ buffer->vq = vq;
>+ buffer->size = 0;
>+ buffer->offset = 0;
>+ QSIMPLEQ_INSERT_TAIL(&stream->queue, buffer, entry);
> continue;
>
> rx_err:
>@@ -1086,7 +1069,6 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
> virtio_add_queue(vdev, 64, virtio_snd_handle_tx_xfer);
> vsnd->queues[VIRTIO_SND_VQ_RX] =
> virtio_add_queue(vdev, 64, virtio_snd_handle_rx_xfer);
>- qemu_mutex_init(&vsnd->cmdq_mutex);
> QTAILQ_INIT(&vsnd->cmdq);
> QSIMPLEQ_INIT(&vsnd->invalid);
>
>@@ -1154,52 +1136,50 @@ static void virtio_snd_pcm_out_cb(void *data, int available)
> VirtIOSoundPCMBuffer *buffer;
> size_t size;
>
>- WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
>- while (!QSIMPLEQ_EMPTY(&stream->queue)) {
>- buffer = QSIMPLEQ_FIRST(&stream->queue);
>- if (!virtio_queue_ready(buffer->vq)) {
>- return;
>+ while (!QSIMPLEQ_EMPTY(&stream->queue)) {
>+ buffer = QSIMPLEQ_FIRST(&stream->queue);
>+ if (!virtio_queue_ready(buffer->vq)) {
>+ return;
>+ }
>+ if (!stream->active) {
>+ /* Stream has stopped, so do not perform audio_be_write. */
>+ return_tx_buffer(stream, buffer);
>+ continue;
>+ }
>+ if (!buffer->populated) {
>+ iov_to_buf(buffer->elem->out_sg,
>+ buffer->elem->out_num,
>+ sizeof(virtio_snd_pcm_xfer),
>+ buffer->data,
>+ buffer->size);
>+ buffer->populated = true;
>+ }
>+ for (;;) {
>+ size = audio_be_write(stream->s->audio_be,
>+ stream->voice.out,
>+ buffer->data + buffer->offset,
>+ MIN(buffer->size, available));
>+ assert(size <= MIN(buffer->size, available));
>+ if (size == 0) {
>+ /* break out of both loops */
>+ available = 0;
>+ break;
> }
>- if (!stream->active) {
>- /* Stream has stopped, so do not perform audio_be_write. */
>+ buffer->size -= size;
>+ buffer->offset += size;
>+ available -= size;
>+ update_latency(stream, size);
>+ if (buffer->size < 1) {
> return_tx_buffer(stream, buffer);
>- continue;
>- }
>- if (!buffer->populated) {
>- iov_to_buf(buffer->elem->out_sg,
>- buffer->elem->out_num,
>- sizeof(virtio_snd_pcm_xfer),
>- buffer->data,
>- buffer->size);
>- buffer->populated = true;
>- }
>- for (;;) {
>- size = audio_be_write(stream->s->audio_be,
>- stream->voice.out,
>- buffer->data + buffer->offset,
>- MIN(buffer->size, available));
>- assert(size <= MIN(buffer->size, available));
>- if (size == 0) {
>- /* break out of both loops */
>- available = 0;
>- break;
>- }
>- buffer->size -= size;
>- buffer->offset += size;
>- available -= size;
>- update_latency(stream, size);
>- if (buffer->size < 1) {
>- return_tx_buffer(stream, buffer);
>- break;
>- }
>- if (!available) {
>- break;
>- }
>+ break;
> }
> if (!available) {
> break;
> }
> }
>+ if (!available) {
>+ break;
>+ }
> }
> }
>
>@@ -1250,55 +1230,53 @@ static void virtio_snd_pcm_in_cb(void *data, int available)
> VirtIOSoundPCMBuffer *buffer;
> size_t size, max_size, to_read;
>
>- WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
>- while (!QSIMPLEQ_EMPTY(&stream->queue)) {
>- buffer = QSIMPLEQ_FIRST(&stream->queue);
>- if (!virtio_queue_ready(buffer->vq)) {
>- return;
>- }
>- if (!stream->active) {
>- /* Stream has stopped, so do not perform audio_be_read. */
>- return_rx_buffer(stream, buffer);
>- continue;
>- }
>+ while (!QSIMPLEQ_EMPTY(&stream->queue)) {
>+ buffer = QSIMPLEQ_FIRST(&stream->queue);
>+ if (!virtio_queue_ready(buffer->vq)) {
>+ return;
>+ }
>+ if (!stream->active) {
>+ /* Stream has stopped, so do not perform audio_be_read. */
>+ return_rx_buffer(stream, buffer);
>+ continue;
>+ }
>+
>+ max_size = iov_size(buffer->elem->in_sg, buffer->elem->in_num);
>+ if (max_size <= sizeof(virtio_snd_pcm_status)) {
>+ return_rx_buffer(stream, buffer);
>+ continue;
>+ }
>+ max_size -= sizeof(virtio_snd_pcm_status);
>
>- max_size = iov_size(buffer->elem->in_sg, buffer->elem->in_num);
>- if (max_size <= sizeof(virtio_snd_pcm_status)) {
>+ for (;;) {
>+ if (buffer->size >= max_size) {
> return_rx_buffer(stream, buffer);
>- continue;
>+ break;
> }
>- max_size -= sizeof(virtio_snd_pcm_status);
>-
>- for (;;) {
>- if (buffer->size >= max_size) {
>- return_rx_buffer(stream, buffer);
>- break;
>- }
>- to_read = stream->params.period_bytes - buffer->size;
>- to_read = MIN(to_read, available);
>- to_read = MIN(to_read, max_size - buffer->size);
>- size = audio_be_read(stream->s->audio_be,
>- stream->voice.in,
>- buffer->data + buffer->size,
>- to_read);
>- if (!size) {
>- available = 0;
>- break;
>- }
>- buffer->size += size;
>- available -= size;
>- if (buffer->size >= stream->params.period_bytes) {
>- return_rx_buffer(stream, buffer);
>- break;
>- }
>- if (!available) {
>- break;
>- }
>+ to_read = stream->params.period_bytes - buffer->size;
>+ to_read = MIN(to_read, available);
>+ to_read = MIN(to_read, max_size - buffer->size);
>+ size = audio_be_read(stream->s->audio_be,
>+ stream->voice.in,
>+ buffer->data + buffer->size,
>+ to_read);
>+ if (!size) {
>+ available = 0;
>+ break;
>+ }
>+ buffer->size += size;
>+ available -= size;
>+ if (buffer->size >= stream->params.period_bytes) {
>+ return_rx_buffer(stream, buffer);
>+ break;
> }
> if (!available) {
> break;
> }
> }
>+ if (!available) {
>+ break;
>+ }
> }
> }
>
>@@ -1315,11 +1293,9 @@ static inline void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream)
> (stream->info.direction == VIRTIO_SND_D_OUTPUT) ? return_tx_buffer :
> return_rx_buffer;
>
>- WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
>- while (!QSIMPLEQ_EMPTY(&stream->queue)) {
>- buffer = QSIMPLEQ_FIRST(&stream->queue);
>- cb(stream, buffer);
>- }
>+ while (!QSIMPLEQ_EMPTY(&stream->queue)) {
>+ buffer = QSIMPLEQ_FIRST(&stream->queue);
>+ cb(stream, buffer);
> }
> }
>
>@@ -1338,14 +1314,12 @@ static void virtio_snd_unrealize(DeviceState *dev)
> if (stream) {
> virtio_snd_process_cmdq(stream->s);
> virtio_snd_pcm_close(stream);
>- qemu_mutex_destroy(&stream->queue_mutex);
> g_free(stream);
> }
> }
> g_free(vsnd->pcm.streams);
> }
> g_free(vsnd->pcm.pcm_params);
>- qemu_mutex_destroy(&vsnd->cmdq_mutex);
> virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]);
> virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_EVENT]);
> virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_TX]);
>@@ -1366,12 +1340,10 @@ static void virtio_snd_reset(VirtIODevice *vdev)
> */
> g_assert(QSIMPLEQ_EMPTY(&vsnd->invalid));
>
>- WITH_QEMU_LOCK_GUARD(&vsnd->cmdq_mutex) {
>- while (!QTAILQ_EMPTY(&vsnd->cmdq)) {
>- cmd = QTAILQ_FIRST(&vsnd->cmdq);
>- QTAILQ_REMOVE(&vsnd->cmdq, cmd, next);
>- virtio_snd_ctrl_cmd_free(cmd);
>- }
>+ while (!QTAILQ_EMPTY(&vsnd->cmdq)) {
>+ cmd = QTAILQ_FIRST(&vsnd->cmdq);
>+ QTAILQ_REMOVE(&vsnd->cmdq, cmd, next);
>+ virtio_snd_ctrl_cmd_free(cmd);
> }
> }
>
>diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
>index e28f1be5db9..fce7d1feea2 100644
>--- a/include/hw/audio/virtio-snd.h
>+++ b/include/hw/audio/virtio-snd.h
>@@ -146,7 +146,6 @@ struct VirtIOSoundPCMStream {
> SWVoiceIn *in;
> SWVoiceOut *out;
> } voice;
>- QemuMutex queue_mutex;
> bool active;
> uint32_t latency_bytes;
> QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) queue;
>@@ -218,9 +217,7 @@ struct VirtIOSound {
> AudioBackend *audio_be;
> VMChangeStateEntry *vmstate;
> virtio_snd_config snd_conf;
>- QemuMutex cmdq_mutex;
> QTAILQ_HEAD(, virtio_snd_ctrl_command) cmdq;
>- bool processing_cmdq;
> /*
> * Convenience queue to keep track of invalid tx/rx queue messages inside
> * the tx/rx callbacks.
>--
>2.47.3
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 2/9] hw/audio/virtio-sound: allocate an array of streams
2026-06-26 12:35 [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support Alexander Mikhalitsyn
2026-06-26 12:35 ` [PATCH v3 1/9] hw/audio/virtio-sound: remove command and stream mutexes Alexander Mikhalitsyn
@ 2026-06-26 12:35 ` Alexander Mikhalitsyn
2026-06-29 7:44 ` Manos Pitsidianakis
2026-06-26 12:35 ` [PATCH v3 3/9] hw/audio/virtio-sound: free all stream buffers on reset Alexander Mikhalitsyn
` (7 subsequent siblings)
9 siblings, 1 reply; 26+ messages in thread
From: Alexander Mikhalitsyn @ 2026-06-26 12:35 UTC (permalink / raw)
To: qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
From: Volker Rümelin <vr_qemu@t-online.de>
It is much easier to migrate an array of structs than individual
structs that are accessed via a pointer to a pointer to an array
of pointers to struct.
For this reason, allocate an array of streams in
virtio_snd_realize() and initialise all stream variables that
are constant at runtime immediately after allocation.
This makes it easier to remove the virtio_snd_set_pcm_params()
and virtio_snd_pcm_prepare() calls in the realisation phase and
to migrate the audio streams of the virtio sound device after
the next few patches.
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
[AM: there were too many conflicts, I did `git checkout --ours -- <.>`
and then reimplemented the patch idea
/AM]
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
v3:
As suggested by Marc-André Lureau:
- drop VirtIOSoundPCMStream's id field
---
hw/audio/virtio-snd.c | 34 +++++++++++++++++++++-------------
include/hw/audio/virtio-snd.h | 2 +-
2 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 6eb31e2838e..859c2770195 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -436,12 +436,9 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
stream = virtio_snd_pcm_get_stream(s, stream_id);
if (stream == NULL) {
- stream = g_new0(VirtIOSoundPCMStream, 1);
+ stream = &s->streams[stream_id];
stream->active = false;
- stream->id = stream_id;
- stream->s = s;
stream->latency_bytes = 0;
- QSIMPLEQ_INIT(&stream->queue);
/*
* stream_id >= s->snd_conf.streams was checked before so this is
@@ -451,14 +448,6 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
}
virtio_snd_get_qemu_audsettings(&as, params);
- stream->info.direction = stream_id < s->snd_conf.streams / 2 +
- (s->snd_conf.streams & 1) ? VIRTIO_SND_D_OUTPUT : VIRTIO_SND_D_INPUT;
- stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID;
- stream->info.features = 0;
- stream->info.channels_min = 1;
- stream->info.channels_max = as.nchannels;
- stream->info.formats = supported_formats;
- stream->info.rates = supported_rates;
stream->params = *params;
stream->positions[0] = VIRTIO_SND_CHMAP_FL;
@@ -1046,6 +1035,24 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
vsnd->vmstate =
qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd);
+ vsnd->streams = g_new0(VirtIOSoundPCMStream, vsnd->snd_conf.streams);
+
+ for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
+ VirtIOSoundPCMStream *stream = &vsnd->streams[i];
+
+ stream->s = vsnd;
+ QSIMPLEQ_INIT(&stream->queue);
+ stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID;
+ stream->info.features = 0;
+ stream->info.formats = supported_formats;
+ stream->info.rates = supported_rates;
+ stream->info.direction =
+ i < vsnd->snd_conf.streams / 2 + (vsnd->snd_conf.streams & 1)
+ ? VIRTIO_SND_D_OUTPUT : VIRTIO_SND_D_INPUT;
+ stream->info.channels_min = 1;
+ stream->info.channels_max = 2;
+ }
+
vsnd->pcm.streams =
g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams);
vsnd->pcm.pcm_params =
@@ -1314,12 +1321,13 @@ static void virtio_snd_unrealize(DeviceState *dev)
if (stream) {
virtio_snd_process_cmdq(stream->s);
virtio_snd_pcm_close(stream);
- g_free(stream);
}
}
g_free(vsnd->pcm.streams);
}
g_free(vsnd->pcm.pcm_params);
+ g_free(vsnd->streams);
+ vsnd->streams = NULL;
virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]);
virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_EVENT]);
virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_TX]);
diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
index fce7d1feea2..41c63b3f23b 100644
--- a/include/hw/audio/virtio-snd.h
+++ b/include/hw/audio/virtio-snd.h
@@ -136,7 +136,6 @@ struct VirtIOSoundPCM {
struct VirtIOSoundPCMStream {
virtio_snd_pcm_info info;
virtio_snd_pcm_set_params params;
- uint32_t id;
/* channel position values (VIRTIO_SND_CHMAP_XXX) */
uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
VirtIOSound *s;
@@ -214,6 +213,7 @@ struct VirtIOSound {
VirtQueue *queues[VIRTIO_SND_VQ_MAX];
uint64_t features;
VirtIOSoundPCM pcm;
+ VirtIOSoundPCMStream *streams;
AudioBackend *audio_be;
VMChangeStateEntry *vmstate;
virtio_snd_config snd_conf;
--
2.47.3
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v3 2/9] hw/audio/virtio-sound: allocate an array of streams
2026-06-26 12:35 ` [PATCH v3 2/9] hw/audio/virtio-sound: allocate an array of streams Alexander Mikhalitsyn
@ 2026-06-29 7:44 ` Manos Pitsidianakis
0 siblings, 0 replies; 26+ messages in thread
From: Manos Pitsidianakis @ 2026-06-29 7:44 UTC (permalink / raw)
To: Alexander Mikhalitsyn, qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
On Fri, 26 Jun 2026 15:35, Alexander Mikhalitsyn <alexander@mihalicyn.com> wrote:
>From: Volker Rümelin <vr_qemu@t-online.de>
>
>It is much easier to migrate an array of structs than individual
>structs that are accessed via a pointer to a pointer to an array
>of pointers to struct.
>
>For this reason, allocate an array of streams in
>virtio_snd_realize() and initialise all stream variables that
>are constant at runtime immediately after allocation.
>
>This makes it easier to remove the virtio_snd_set_pcm_params()
>and virtio_snd_pcm_prepare() calls in the realisation phase and
>to migrate the audio streams of the virtio sound device after
>the next few patches.
>
>Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
>[AM: there were too many conflicts, I did `git checkout --ours -- <.>`
> and then reimplemented the patch idea
>/AM]
>Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
>Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>---
>v3:
> As suggested by Marc-André Lureau:
> - drop VirtIOSoundPCMStream's id field
>---
> hw/audio/virtio-snd.c | 34 +++++++++++++++++++++-------------
> include/hw/audio/virtio-snd.h | 2 +-
> 2 files changed, 22 insertions(+), 14 deletions(-)
>
>diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
>index 6eb31e2838e..859c2770195 100644
>--- a/hw/audio/virtio-snd.c
>+++ b/hw/audio/virtio-snd.c
>@@ -436,12 +436,9 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
>
> stream = virtio_snd_pcm_get_stream(s, stream_id);
> if (stream == NULL) {
>- stream = g_new0(VirtIOSoundPCMStream, 1);
>+ stream = &s->streams[stream_id];
> stream->active = false;
>- stream->id = stream_id;
>- stream->s = s;
> stream->latency_bytes = 0;
>- QSIMPLEQ_INIT(&stream->queue);
>
> /*
> * stream_id >= s->snd_conf.streams was checked before so this is
>@@ -451,14 +448,6 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
> }
>
> virtio_snd_get_qemu_audsettings(&as, params);
>- stream->info.direction = stream_id < s->snd_conf.streams / 2 +
>- (s->snd_conf.streams & 1) ? VIRTIO_SND_D_OUTPUT : VIRTIO_SND_D_INPUT;
>- stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID;
>- stream->info.features = 0;
>- stream->info.channels_min = 1;
>- stream->info.channels_max = as.nchannels;
>- stream->info.formats = supported_formats;
>- stream->info.rates = supported_rates;
> stream->params = *params;
>
> stream->positions[0] = VIRTIO_SND_CHMAP_FL;
>@@ -1046,6 +1035,24 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
> vsnd->vmstate =
> qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd);
>
>+ vsnd->streams = g_new0(VirtIOSoundPCMStream, vsnd->snd_conf.streams);
>+
>+ for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
>+ VirtIOSoundPCMStream *stream = &vsnd->streams[i];
>+
>+ stream->s = vsnd;
>+ QSIMPLEQ_INIT(&stream->queue);
>+ stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID;
>+ stream->info.features = 0;
>+ stream->info.formats = supported_formats;
>+ stream->info.rates = supported_rates;
>+ stream->info.direction =
>+ i < vsnd->snd_conf.streams / 2 + (vsnd->snd_conf.streams & 1)
>+ ? VIRTIO_SND_D_OUTPUT : VIRTIO_SND_D_INPUT;
>+ stream->info.channels_min = 1;
>+ stream->info.channels_max = 2;
Why 2 instead of as.nchannels? Does this break support for more than 2
channels?
>+ }
>+
> vsnd->pcm.streams =
> g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams);
> vsnd->pcm.pcm_params =
>@@ -1314,12 +1321,13 @@ static void virtio_snd_unrealize(DeviceState *dev)
> if (stream) {
> virtio_snd_process_cmdq(stream->s);
> virtio_snd_pcm_close(stream);
>- g_free(stream);
> }
> }
> g_free(vsnd->pcm.streams);
> }
> g_free(vsnd->pcm.pcm_params);
>+ g_free(vsnd->streams);
>+ vsnd->streams = NULL;
> virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]);
> virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_EVENT]);
> virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_TX]);
>diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
>index fce7d1feea2..41c63b3f23b 100644
>--- a/include/hw/audio/virtio-snd.h
>+++ b/include/hw/audio/virtio-snd.h
>@@ -136,7 +136,6 @@ struct VirtIOSoundPCM {
> struct VirtIOSoundPCMStream {
> virtio_snd_pcm_info info;
> virtio_snd_pcm_set_params params;
>- uint32_t id;
> /* channel position values (VIRTIO_SND_CHMAP_XXX) */
> uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
> VirtIOSound *s;
>@@ -214,6 +213,7 @@ struct VirtIOSound {
> VirtQueue *queues[VIRTIO_SND_VQ_MAX];
> uint64_t features;
> VirtIOSoundPCM pcm;
>+ VirtIOSoundPCMStream *streams;
> AudioBackend *audio_be;
> VMChangeStateEntry *vmstate;
> virtio_snd_config snd_conf;
>--
>2.47.3
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 3/9] hw/audio/virtio-sound: free all stream buffers on reset
2026-06-26 12:35 [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support Alexander Mikhalitsyn
2026-06-26 12:35 ` [PATCH v3 1/9] hw/audio/virtio-sound: remove command and stream mutexes Alexander Mikhalitsyn
2026-06-26 12:35 ` [PATCH v3 2/9] hw/audio/virtio-sound: allocate an array of streams Alexander Mikhalitsyn
@ 2026-06-26 12:35 ` Alexander Mikhalitsyn
2026-06-29 7:50 ` Manos Pitsidianakis
2026-06-26 12:35 ` [PATCH v3 4/9] hw/audio/virtio-sound: split out virtio_snd_pcm_start_stop() Alexander Mikhalitsyn
` (6 subsequent siblings)
9 siblings, 1 reply; 26+ messages in thread
From: Alexander Mikhalitsyn @ 2026-06-26 12:35 UTC (permalink / raw)
To: qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
From: Volker Rümelin <vr_qemu@t-online.de>
All remaining stream buffers in the stream queues must
be freed after a reset. This is the initial state of the
virtio-sound device.
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
[AM: trivial variable rename s -> vsnd]
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/audio/virtio-snd.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 859c2770195..8f4421ba844 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -1340,6 +1340,7 @@ static void virtio_snd_reset(VirtIODevice *vdev)
{
VirtIOSound *vsnd = VIRTIO_SND(vdev);
virtio_snd_ctrl_command *cmd;
+ uint32_t i;
/*
* Sanity check that the invalid buffer message queue is emptied at the end
@@ -1353,6 +1354,16 @@ static void virtio_snd_reset(VirtIODevice *vdev)
QTAILQ_REMOVE(&vsnd->cmdq, cmd, next);
virtio_snd_ctrl_cmd_free(cmd);
}
+
+ for (i = 0; i < vsnd->snd_conf.streams; i++) {
+ VirtIOSoundPCMStream *stream = &vsnd->streams[i];
+ VirtIOSoundPCMBuffer *buffer;
+
+ while ((buffer = QSIMPLEQ_FIRST(&stream->queue))) {
+ QSIMPLEQ_REMOVE_HEAD(&stream->queue, entry);
+ virtio_snd_pcm_buffer_free(buffer);
+ }
+ }
}
static void virtio_snd_class_init(ObjectClass *klass, const void *data)
--
2.47.3
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v3 3/9] hw/audio/virtio-sound: free all stream buffers on reset
2026-06-26 12:35 ` [PATCH v3 3/9] hw/audio/virtio-sound: free all stream buffers on reset Alexander Mikhalitsyn
@ 2026-06-29 7:50 ` Manos Pitsidianakis
0 siblings, 0 replies; 26+ messages in thread
From: Manos Pitsidianakis @ 2026-06-29 7:50 UTC (permalink / raw)
To: Alexander Mikhalitsyn, qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
On Fri, 26 Jun 2026 15:35, Alexander Mikhalitsyn <alexander@mihalicyn.com> wrote:
>From: Volker Rümelin <vr_qemu@t-online.de>
>
>All remaining stream buffers in the stream queues must
>be freed after a reset. This is the initial state of the
>virtio-sound device.
>
>Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
>[AM: trivial variable rename s -> vsnd]
>Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
>Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>---
> hw/audio/virtio-snd.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
>diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
>index 859c2770195..8f4421ba844 100644
>--- a/hw/audio/virtio-snd.c
>+++ b/hw/audio/virtio-snd.c
>@@ -1340,6 +1340,7 @@ static void virtio_snd_reset(VirtIODevice *vdev)
> {
> VirtIOSound *vsnd = VIRTIO_SND(vdev);
> virtio_snd_ctrl_command *cmd;
>+ uint32_t i;
>
> /*
> * Sanity check that the invalid buffer message queue is emptied at the end
>@@ -1353,6 +1354,16 @@ static void virtio_snd_reset(VirtIODevice *vdev)
> QTAILQ_REMOVE(&vsnd->cmdq, cmd, next);
> virtio_snd_ctrl_cmd_free(cmd);
> }
>+
>+ for (i = 0; i < vsnd->snd_conf.streams; i++) {
Or:
+ for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
Either way,
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
>+ VirtIOSoundPCMStream *stream = &vsnd->streams[i];
>+ VirtIOSoundPCMBuffer *buffer;
>+
>+ while ((buffer = QSIMPLEQ_FIRST(&stream->queue))) {
>+ QSIMPLEQ_REMOVE_HEAD(&stream->queue, entry);
>+ virtio_snd_pcm_buffer_free(buffer);
>+ }
>+ }
> }
>
> static void virtio_snd_class_init(ObjectClass *klass, const void *data)
>--
>2.47.3
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 4/9] hw/audio/virtio-sound: split out virtio_snd_pcm_start_stop()
2026-06-26 12:35 [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support Alexander Mikhalitsyn
` (2 preceding siblings ...)
2026-06-26 12:35 ` [PATCH v3 3/9] hw/audio/virtio-sound: free all stream buffers on reset Alexander Mikhalitsyn
@ 2026-06-26 12:35 ` Alexander Mikhalitsyn
2026-06-29 7:51 ` Manos Pitsidianakis
2026-06-26 12:35 ` [PATCH v3 5/9] hw/audio/virtio-sound: add stream state variable Alexander Mikhalitsyn
` (5 subsequent siblings)
9 siblings, 1 reply; 26+ messages in thread
From: Alexander Mikhalitsyn @ 2026-06-26 12:35 UTC (permalink / raw)
To: qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
From: Volker Rümelin <vr_qemu@t-online.de>
Split out virtio_snd_pcm_start_stop(). This is a preparation
for the next patch so that it doesn't become too big.
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
[AM: there were too many conflicts, I did `git checkout --ours -- <.>`
and then reimplemented the patch idea
/AM]
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
v3:
- resurrected error_report(..) as suggested by Marc-André Lureau
---
hw/audio/trace-events | 3 ++-
hw/audio/virtio-snd.c | 59 ++++++++++++++++++++++++++++---------------
2 files changed, 41 insertions(+), 21 deletions(-)
diff --git a/hw/audio/trace-events b/hw/audio/trace-events
index 30f59215453..75d1fb37bd9 100644
--- a/hw/audio/trace-events
+++ b/hw/audio/trace-events
@@ -53,7 +53,8 @@ virtio_snd_unrealize(void *snd) "snd %p: unrealize"
virtio_snd_handle_pcm_set_params(uint32_t stream) "VIRTIO_SND_PCM_SET_PARAMS called for stream %"PRIu32
virtio_snd_handle_ctrl(void *vdev, void *vq) "snd %p: handle ctrl event for queue %p"
virtio_snd_handle_pcm_info(uint32_t stream) "VIRTIO_SND_R_PCM_INFO called for stream %"PRIu32
-virtio_snd_handle_pcm_start_stop(const char *code, uint32_t stream) "%s called for stream %"PRIu32
+virtio_snd_handle_pcm_start(uint32_t stream) "VIRTIO_SND_R_PCM_START called for stream %"PRIu32
+virtio_snd_handle_pcm_stop(uint32_t stream) "VIRTIO_SND_R_PCM_STOP called for stream %"PRIu32
virtio_snd_handle_pcm_release(uint32_t stream) "VIRTIO_SND_PCM_RELEASE called for stream %"PRIu32
virtio_snd_handle_code(uint32_t val, const char *code) "ctrl code msg val = %"PRIu32" == %s"
virtio_snd_handle_chmap_info(void) "VIRTIO_SND_CHMAP_INFO called"
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 8f4421ba844..300ba13ffeb 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -521,7 +521,44 @@ static void virtio_snd_handle_pcm_prepare(VirtIOSound *s,
}
/*
- * Handles VIRTIO_SND_R_PCM_START.
+ * Starts/Stops a VirtIOSound card stream.
+ * Returns the response status code. (VIRTIO_SND_S_*).
+ *
+ * @s: VirtIOSound device
+ * @stream_id: stream id
+ * @start: whether to start or stop the stream
+ */
+static uint32_t virtio_snd_pcm_start_stop(VirtIOSound *s,
+ uint32_t stream_id,
+ bool start)
+{
+ VirtIOSoundPCMStream *stream;
+
+ stream = virtio_snd_pcm_get_stream(s, stream_id);
+ if (!stream) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Invalid stream id: %"PRIu32 "\n", __func__, stream_id);
+ return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
+ }
+
+ if (start) {
+ trace_virtio_snd_handle_pcm_start(stream_id);
+ } else {
+ trace_virtio_snd_handle_pcm_stop(stream_id);
+ }
+
+ stream->active = start;
+ if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
+ audio_be_set_active_out(s->audio_be, stream->voice.out, start);
+ } else {
+ audio_be_set_active_in(s->audio_be, stream->voice.in, start);
+ }
+
+ return cpu_to_le32(VIRTIO_SND_S_OK);
+}
+
+/*
+ * Handles VIRTIO_SND_R_PCM_START and VIRTIO_SND_R_PCM_STOP.
*
* @s: VirtIOSound device
* @cmd: The request command queue element from VirtIOSound cmdq field
@@ -531,7 +568,6 @@ static void virtio_snd_handle_pcm_start_stop(VirtIOSound *s,
virtio_snd_ctrl_command *cmd,
bool start)
{
- VirtIOSoundPCMStream *stream;
virtio_snd_pcm_hdr req;
uint32_t stream_id;
size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
@@ -549,24 +585,7 @@ static void virtio_snd_handle_pcm_start_stop(VirtIOSound *s,
}
stream_id = le32_to_cpu(req.stream_id);
- cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
- trace_virtio_snd_handle_pcm_start_stop(start ? "VIRTIO_SND_R_PCM_START" :
- "VIRTIO_SND_R_PCM_STOP", stream_id);
-
- stream = virtio_snd_pcm_get_stream(s, stream_id);
- if (stream) {
- stream->active = start;
- if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
- audio_be_set_active_out(s->audio_be, stream->voice.out, start);
- } else {
- audio_be_set_active_in(s->audio_be, stream->voice.in, start);
- }
- } else {
- error_report("Invalid stream id: %"PRIu32, stream_id);
- cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
- return;
- }
- stream->active = start;
+ cmd->resp.code = virtio_snd_pcm_start_stop(s, stream_id, start);
}
/*
--
2.47.3
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v3 4/9] hw/audio/virtio-sound: split out virtio_snd_pcm_start_stop()
2026-06-26 12:35 ` [PATCH v3 4/9] hw/audio/virtio-sound: split out virtio_snd_pcm_start_stop() Alexander Mikhalitsyn
@ 2026-06-29 7:51 ` Manos Pitsidianakis
0 siblings, 0 replies; 26+ messages in thread
From: Manos Pitsidianakis @ 2026-06-29 7:51 UTC (permalink / raw)
To: Alexander Mikhalitsyn, qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
On Fri, 26 Jun 2026 15:35, Alexander Mikhalitsyn <alexander@mihalicyn.com> wrote:
>From: Volker Rümelin <vr_qemu@t-online.de>
>
>Split out virtio_snd_pcm_start_stop(). This is a preparation
>for the next patch so that it doesn't become too big.
>
>Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
>[AM: there were too many conflicts, I did `git checkout --ours -- <.>`
> and then reimplemented the patch idea
>/AM]
>Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
>Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>---
>v3:
> - resurrected error_report(..) as suggested by Marc-André Lureau
>---
> hw/audio/trace-events | 3 ++-
> hw/audio/virtio-snd.c | 59 ++++++++++++++++++++++++++++---------------
> 2 files changed, 41 insertions(+), 21 deletions(-)
>
>diff --git a/hw/audio/trace-events b/hw/audio/trace-events
>index 30f59215453..75d1fb37bd9 100644
>--- a/hw/audio/trace-events
>+++ b/hw/audio/trace-events
>@@ -53,7 +53,8 @@ virtio_snd_unrealize(void *snd) "snd %p: unrealize"
> virtio_snd_handle_pcm_set_params(uint32_t stream) "VIRTIO_SND_PCM_SET_PARAMS called for stream %"PRIu32
> virtio_snd_handle_ctrl(void *vdev, void *vq) "snd %p: handle ctrl event for queue %p"
> virtio_snd_handle_pcm_info(uint32_t stream) "VIRTIO_SND_R_PCM_INFO called for stream %"PRIu32
>-virtio_snd_handle_pcm_start_stop(const char *code, uint32_t stream) "%s called for stream %"PRIu32
>+virtio_snd_handle_pcm_start(uint32_t stream) "VIRTIO_SND_R_PCM_START called for stream %"PRIu32
>+virtio_snd_handle_pcm_stop(uint32_t stream) "VIRTIO_SND_R_PCM_STOP called for stream %"PRIu32
> virtio_snd_handle_pcm_release(uint32_t stream) "VIRTIO_SND_PCM_RELEASE called for stream %"PRIu32
> virtio_snd_handle_code(uint32_t val, const char *code) "ctrl code msg val = %"PRIu32" == %s"
> virtio_snd_handle_chmap_info(void) "VIRTIO_SND_CHMAP_INFO called"
>diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
>index 8f4421ba844..300ba13ffeb 100644
>--- a/hw/audio/virtio-snd.c
>+++ b/hw/audio/virtio-snd.c
>@@ -521,7 +521,44 @@ static void virtio_snd_handle_pcm_prepare(VirtIOSound *s,
> }
>
> /*
>- * Handles VIRTIO_SND_R_PCM_START.
>+ * Starts/Stops a VirtIOSound card stream.
>+ * Returns the response status code. (VIRTIO_SND_S_*).
>+ *
>+ * @s: VirtIOSound device
>+ * @stream_id: stream id
>+ * @start: whether to start or stop the stream
>+ */
>+static uint32_t virtio_snd_pcm_start_stop(VirtIOSound *s,
>+ uint32_t stream_id,
>+ bool start)
>+{
>+ VirtIOSoundPCMStream *stream;
>+
>+ stream = virtio_snd_pcm_get_stream(s, stream_id);
>+ if (!stream) {
>+ qemu_log_mask(LOG_GUEST_ERROR,
>+ "%s: Invalid stream id: %"PRIu32 "\n", __func__, stream_id);
Minor formatting nit:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Invalid stream id: %"PRIu32 "\n",
+ __func__, stream_id);
>+ return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
>+ }
>+
>+ if (start) {
>+ trace_virtio_snd_handle_pcm_start(stream_id);
>+ } else {
>+ trace_virtio_snd_handle_pcm_stop(stream_id);
>+ }
Let's move the trace_*() calls at the start of the function, before the
error checking, like it used to be.
>+
>+ stream->active = start;
>+ if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
>+ audio_be_set_active_out(s->audio_be, stream->voice.out, start);
>+ } else {
>+ audio_be_set_active_in(s->audio_be, stream->voice.in, start);
>+ }
>+
>+ return cpu_to_le32(VIRTIO_SND_S_OK);
>+}
>+
>+/*
>+ * Handles VIRTIO_SND_R_PCM_START and VIRTIO_SND_R_PCM_STOP.
> *
> * @s: VirtIOSound device
> * @cmd: The request command queue element from VirtIOSound cmdq field
>@@ -531,7 +568,6 @@ static void virtio_snd_handle_pcm_start_stop(VirtIOSound *s,
> virtio_snd_ctrl_command *cmd,
> bool start)
> {
>- VirtIOSoundPCMStream *stream;
> virtio_snd_pcm_hdr req;
> uint32_t stream_id;
> size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
>@@ -549,24 +585,7 @@ static void virtio_snd_handle_pcm_start_stop(VirtIOSound *s,
> }
>
> stream_id = le32_to_cpu(req.stream_id);
>- cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
>- trace_virtio_snd_handle_pcm_start_stop(start ? "VIRTIO_SND_R_PCM_START" :
>- "VIRTIO_SND_R_PCM_STOP", stream_id);
>-
>- stream = virtio_snd_pcm_get_stream(s, stream_id);
>- if (stream) {
>- stream->active = start;
>- if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
>- audio_be_set_active_out(s->audio_be, stream->voice.out, start);
>- } else {
>- audio_be_set_active_in(s->audio_be, stream->voice.in, start);
>- }
>- } else {
>- error_report("Invalid stream id: %"PRIu32, stream_id);
>- cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
>- return;
>- }
>- stream->active = start;
>+ cmd->resp.code = virtio_snd_pcm_start_stop(s, stream_id, start);
> }
>
> /*
>--
>2.47.3
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 5/9] hw/audio/virtio-sound: add stream state variable
2026-06-26 12:35 [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support Alexander Mikhalitsyn
` (3 preceding siblings ...)
2026-06-26 12:35 ` [PATCH v3 4/9] hw/audio/virtio-sound: split out virtio_snd_pcm_start_stop() Alexander Mikhalitsyn
@ 2026-06-26 12:35 ` Alexander Mikhalitsyn
2026-06-26 14:12 ` marcandre.lureau
2026-06-29 7:58 ` Manos Pitsidianakis
2026-06-26 12:35 ` [PATCH v3 6/9] hw/audio/virtio-sound: introduce virtio_snd_pcm_open() Alexander Mikhalitsyn
` (4 subsequent siblings)
9 siblings, 2 replies; 26+ messages in thread
From: Alexander Mikhalitsyn @ 2026-06-26 12:35 UTC (permalink / raw)
To: qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
From: Volker Rümelin <vr_qemu@t-online.de>
So far, only rudimentary checks have been made to ensure that
the guest only performs state transitions permitted in
virtio-v1.2-csd01 5.14.6.6.1 PCM Command Lifecycle. Add a state
variable per audio stream and check all state transitions.
Because only permitted state transitions are possible, only one
copy of the audio stream parameters is required and these do not
need to be initialised with default values.
The state variable will also make it easier to restore the audio
stream after migration.
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
[AM: there were too many conflicts, I did `git checkout --ours -- <.>`
and then reimplemented the patch idea
/AM]
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
---
v3:
- explicitly call virtio_snd_pcm_close() from unrealize
- remove a call to virtio_snd_pcm_flush() from virtio_snd_pcm_close()
[ ^ this was my rebase mistake ]
---
hw/audio/virtio-snd.c | 196 +++++++++++++++++++---------------
include/hw/audio/virtio-snd.h | 18 +---
2 files changed, 109 insertions(+), 105 deletions(-)
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 300ba13ffeb..68d737478f5 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -30,11 +30,30 @@
#define VIRTIO_SOUND_CHMAP_DEFAULT 0
#define VIRTIO_SOUND_HDA_FN_NID 0
+#define VSND_PCMSTREAM_STATE_F_PARAMS_SET 0x10000
+#define VSND_PCMSTREAM_STATE_F_PREPARED 0x20000
+#define VSND_PCMSTREAM_STATE_F_ACTIVE 0x40000
+
+#define VSND_PCMSTREAM_STATE_UNINITIALIZED 0
+#define VSND_PCMSTREAM_STATE_PARAMS_SET (1 \
+ | VSND_PCMSTREAM_STATE_F_PARAMS_SET)
+#define VSND_PCMSTREAM_STATE_PREPARED (2 \
+ | VSND_PCMSTREAM_STATE_F_PARAMS_SET \
+ | VSND_PCMSTREAM_STATE_F_PREPARED)
+#define VSND_PCMSTREAM_STATE_STARTED (4 \
+ | VSND_PCMSTREAM_STATE_F_PARAMS_SET \
+ | VSND_PCMSTREAM_STATE_F_PREPARED \
+ | VSND_PCMSTREAM_STATE_F_ACTIVE)
+#define VSND_PCMSTREAM_STATE_STOPPED (6 \
+ | VSND_PCMSTREAM_STATE_F_PARAMS_SET \
+ | VSND_PCMSTREAM_STATE_F_PREPARED)
+#define VSND_PCMSTREAM_STATE_RELEASED (7 \
+ | VSND_PCMSTREAM_STATE_F_PARAMS_SET)
+
static void virtio_snd_pcm_out_cb(void *data, int available);
static void virtio_snd_process_cmdq(VirtIOSound *s);
static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream);
static void virtio_snd_pcm_in_cb(void *data, int available);
-static void virtio_snd_unrealize(DeviceState *dev);
static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8)
| BIT(VIRTIO_SND_PCM_FMT_U8)
@@ -129,7 +148,7 @@ static VirtIOSoundPCMStream *virtio_snd_pcm_get_stream(VirtIOSound *s,
uint32_t stream_id)
{
return stream_id >= s->snd_conf.streams ? NULL :
- s->pcm.streams[stream_id];
+ &s->streams[stream_id];
}
/*
@@ -141,8 +160,8 @@ static VirtIOSoundPCMStream *virtio_snd_pcm_get_stream(VirtIOSound *s,
static virtio_snd_pcm_set_params *virtio_snd_pcm_get_params(VirtIOSound *s,
uint32_t stream_id)
{
- return stream_id >= s->snd_conf.streams ? NULL
- : &s->pcm.pcm_params[stream_id];
+ return stream_id >= s->snd_conf.streams ? NULL :
+ &s->streams[stream_id].params;
}
/*
@@ -245,11 +264,10 @@ static void virtio_snd_handle_pcm_info(VirtIOSound *s,
/*
* Set the given stream params.
- * Called by both virtio_snd_handle_pcm_set_params and during device
- * initialization.
* Returns the response status code. (VIRTIO_SND_S_*).
*
* @s: VirtIOSound device
+ * @stream_id: stream id
* @params: The PCM params as defined in the virtio specification
*/
static
@@ -257,14 +275,25 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
uint32_t stream_id,
virtio_snd_pcm_set_params *params)
{
+ VirtIOSoundPCMStream *stream;
virtio_snd_pcm_set_params *st_params;
- if (stream_id >= s->snd_conf.streams || s->pcm.pcm_params == NULL) {
+ if (stream_id >= s->snd_conf.streams) {
virtio_error(VIRTIO_DEVICE(s), "Streams have not been initialized.\n");
return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
}
- st_params = virtio_snd_pcm_get_params(s, stream_id);
+ stream = virtio_snd_pcm_get_stream(s, stream_id);
+
+ switch (stream->state) {
+ case VSND_PCMSTREAM_STATE_UNINITIALIZED:
+ case VSND_PCMSTREAM_STATE_PARAMS_SET:
+ case VSND_PCMSTREAM_STATE_PREPARED:
+ case VSND_PCMSTREAM_STATE_RELEASED:
+ break;
+ default:
+ return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
+ }
if (params->channels < 1 || params->channels > AUDIO_MAX_CHANNELS) {
error_report("Number of channels is not supported.");
@@ -281,6 +310,8 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
}
+ st_params = virtio_snd_pcm_get_params(s, stream_id);
+
st_params->buffer_bytes = le32_to_cpu(params->buffer_bytes);
st_params->period_bytes = le32_to_cpu(params->period_bytes);
st_params->features = le32_to_cpu(params->features);
@@ -289,6 +320,13 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
st_params->format = params->format;
st_params->rate = params->rate;
+ if (stream->state & VSND_PCMSTREAM_STATE_F_PREPARED) {
+ /* implicit VIRTIO_SND_R_PCM_RELEASE */
+ virtio_snd_pcm_flush(stream);
+ }
+
+ stream->state = VSND_PCMSTREAM_STATE_PARAMS_SET;
+
return cpu_to_le32(VIRTIO_SND_S_OK);
}
@@ -398,15 +436,12 @@ static void virtio_snd_get_qemu_audsettings(audsettings *as,
*/
static void virtio_snd_pcm_close(VirtIOSoundPCMStream *stream)
{
- if (stream) {
- virtio_snd_pcm_flush(stream);
- if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
- audio_be_close_out(stream->s->audio_be, stream->voice.out);
- stream->voice.out = NULL;
- } else if (stream->info.direction == VIRTIO_SND_D_INPUT) {
- audio_be_close_in(stream->s->audio_be, stream->voice.in);
- stream->voice.in = NULL;
- }
+ if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
+ audio_be_close_out(stream->s->audio_be, stream->voice.out);
+ stream->voice.out = NULL;
+ } else if (stream->info.direction == VIRTIO_SND_D_INPUT) {
+ audio_be_close_in(stream->s->audio_be, stream->voice.in);
+ stream->voice.in = NULL;
}
}
@@ -423,32 +458,23 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
virtio_snd_pcm_set_params *params;
VirtIOSoundPCMStream *stream;
- if (s->pcm.streams == NULL ||
- s->pcm.pcm_params == NULL ||
- stream_id >= s->snd_conf.streams) {
+ stream = virtio_snd_pcm_get_stream(s, stream_id);
+ if (!stream) {
return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
}
- params = virtio_snd_pcm_get_params(s, stream_id);
- if (params == NULL) {
+ switch (stream->state) {
+ case VSND_PCMSTREAM_STATE_PARAMS_SET:
+ case VSND_PCMSTREAM_STATE_PREPARED:
+ case VSND_PCMSTREAM_STATE_RELEASED:
+ break;
+ default:
return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
}
- stream = virtio_snd_pcm_get_stream(s, stream_id);
- if (stream == NULL) {
- stream = &s->streams[stream_id];
- stream->active = false;
- stream->latency_bytes = 0;
-
- /*
- * stream_id >= s->snd_conf.streams was checked before so this is
- * in-bounds
- */
- s->pcm.streams[stream_id] = stream;
- }
+ params = virtio_snd_pcm_get_params(s, stream_id);
virtio_snd_get_qemu_audsettings(&as, params);
- stream->params = *params;
stream->positions[0] = VIRTIO_SND_CHMAP_FL;
stream->positions[1] = VIRTIO_SND_CHMAP_FR;
@@ -472,6 +498,8 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
audio_be_set_volume_in_lr(s->audio_be, stream->voice.in, 0, 255, 255);
}
+ stream->state = VSND_PCMSTREAM_STATE_PREPARED;
+
return cpu_to_le32(VIRTIO_SND_S_OK);
}
@@ -542,12 +570,28 @@ static uint32_t virtio_snd_pcm_start_stop(VirtIOSound *s,
}
if (start) {
+ switch (stream->state) {
+ case VSND_PCMSTREAM_STATE_PREPARED:
+ case VSND_PCMSTREAM_STATE_STOPPED:
+ break;
+ default:
+ return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
+ }
+
trace_virtio_snd_handle_pcm_start(stream_id);
+ stream->state = VSND_PCMSTREAM_STATE_STARTED;
} else {
+ switch (stream->state) {
+ case VSND_PCMSTREAM_STATE_STARTED:
+ break;
+ default:
+ return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
+ }
+
trace_virtio_snd_handle_pcm_stop(stream_id);
+ stream->state = VSND_PCMSTREAM_STATE_STOPPED;
}
- stream->active = start;
if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
audio_be_set_active_out(s->audio_be, stream->voice.out, start);
} else {
@@ -641,6 +685,15 @@ static void virtio_snd_handle_pcm_release(VirtIOSound *s,
return;
}
+ switch (stream->state) {
+ case VSND_PCMSTREAM_STATE_PREPARED:
+ case VSND_PCMSTREAM_STATE_STOPPED:
+ break;
+ default:
+ cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
+ return;
+ }
+
if (virtio_snd_pcm_get_io_msgs_count(stream)) {
/*
* virtio-v1.2-csd01, 5.14.6.6.5.1,
@@ -655,6 +708,8 @@ static void virtio_snd_handle_pcm_release(VirtIOSound *s,
virtio_snd_pcm_flush(stream);
}
+ stream->state = VSND_PCMSTREAM_STATE_RELEASED;
+
cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
}
@@ -876,12 +931,11 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
}
stream_id = le32_to_cpu(hdr.stream_id);
- if (stream_id >= vsnd->snd_conf.streams
- || vsnd->pcm.streams[stream_id] == NULL) {
+ if (stream_id >= vsnd->snd_conf.streams) {
goto tx_err;
}
- stream = vsnd->pcm.streams[stream_id];
+ stream = &vsnd->streams[stream_id];
if (stream->info.direction != VIRTIO_SND_D_OUTPUT) {
goto tx_err;
}
@@ -956,13 +1010,12 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
}
stream_id = le32_to_cpu(hdr.stream_id);
- if (stream_id >= vsnd->snd_conf.streams
- || !vsnd->pcm.streams[stream_id]) {
+ if (stream_id >= vsnd->snd_conf.streams) {
goto rx_err;
}
- stream = vsnd->pcm.streams[stream_id];
- if (stream == NULL || stream->info.direction != VIRTIO_SND_D_INPUT) {
+ stream = &vsnd->streams[stream_id];
+ if (stream->info.direction != VIRTIO_SND_D_INPUT) {
goto rx_err;
}
@@ -1021,8 +1074,6 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
ERRP_GUARD();
VirtIOSound *vsnd = VIRTIO_SND(dev);
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- virtio_snd_pcm_set_params default_params = { 0 };
- uint32_t status;
trace_virtio_snd_realize(vsnd);
@@ -1059,6 +1110,7 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
VirtIOSoundPCMStream *stream = &vsnd->streams[i];
+ stream->state = VSND_PCMSTREAM_STATE_UNINITIALIZED;
stream->s = vsnd;
QSIMPLEQ_INIT(&stream->queue);
stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID;
@@ -1072,21 +1124,9 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
stream->info.channels_max = 2;
}
- vsnd->pcm.streams =
- g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams);
- vsnd->pcm.pcm_params =
- g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams);
-
virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config));
virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1);
- /* set default params for all streams */
- default_params.features = 0;
- default_params.buffer_bytes = cpu_to_le32(8192);
- default_params.period_bytes = cpu_to_le32(2048);
- default_params.channels = 2;
- default_params.format = VIRTIO_SND_PCM_FMT_S16;
- default_params.rate = VIRTIO_SND_PCM_RATE_48000;
vsnd->queues[VIRTIO_SND_VQ_CONTROL] =
virtio_add_queue(vdev, 64, virtio_snd_handle_ctrl);
vsnd->queues[VIRTIO_SND_VQ_EVENT] =
@@ -1097,28 +1137,6 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
virtio_add_queue(vdev, 64, virtio_snd_handle_rx_xfer);
QTAILQ_INIT(&vsnd->cmdq);
QSIMPLEQ_INIT(&vsnd->invalid);
-
- for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
- status = virtio_snd_set_pcm_params(vsnd, i, &default_params);
- if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
- error_setg(errp,
- "Can't initialize stream params, device responded with %s.",
- print_code(status));
- goto error_cleanup;
- }
- status = virtio_snd_pcm_prepare(vsnd, i);
- if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
- error_setg(errp,
- "Can't prepare streams, device responded with %s.",
- print_code(status));
- goto error_cleanup;
- }
- }
-
- return;
-
-error_cleanup:
- virtio_snd_unrealize(dev);
}
static inline void update_latency(VirtIOSoundPCMStream *s, size_t used)
@@ -1167,7 +1185,7 @@ static void virtio_snd_pcm_out_cb(void *data, int available)
if (!virtio_queue_ready(buffer->vq)) {
return;
}
- if (!stream->active) {
+ if (!(stream->state & VSND_PCMSTREAM_STATE_F_ACTIVE)) {
/* Stream has stopped, so do not perform audio_be_write. */
return_tx_buffer(stream, buffer);
continue;
@@ -1261,7 +1279,7 @@ static void virtio_snd_pcm_in_cb(void *data, int available)
if (!virtio_queue_ready(buffer->vq)) {
return;
}
- if (!stream->active) {
+ if (!(stream->state & VSND_PCMSTREAM_STATE_F_ACTIVE)) {
/* Stream has stopped, so do not perform audio_be_read. */
return_rx_buffer(stream, buffer);
continue;
@@ -1334,17 +1352,16 @@ static void virtio_snd_unrealize(DeviceState *dev)
qemu_del_vm_change_state_handler(vsnd->vmstate);
trace_virtio_snd_unrealize(vsnd);
- if (vsnd->pcm.streams) {
+ if (vsnd->streams) {
+ virtio_snd_process_cmdq(vsnd);
for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
- stream = vsnd->pcm.streams[i];
- if (stream) {
- virtio_snd_process_cmdq(stream->s);
- virtio_snd_pcm_close(stream);
+ stream = &vsnd->streams[i];
+ if (stream->state & VSND_PCMSTREAM_STATE_F_PREPARED) {
+ virtio_snd_pcm_flush(stream);
}
+ virtio_snd_pcm_close(stream);
}
- g_free(vsnd->pcm.streams);
}
- g_free(vsnd->pcm.pcm_params);
g_free(vsnd->streams);
vsnd->streams = NULL;
virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]);
@@ -1378,6 +1395,9 @@ static void virtio_snd_reset(VirtIODevice *vdev)
VirtIOSoundPCMStream *stream = &vsnd->streams[i];
VirtIOSoundPCMBuffer *buffer;
+ virtio_snd_pcm_close(stream);
+ stream->state = VSND_PCMSTREAM_STATE_UNINITIALIZED;
+
while ((buffer = QSIMPLEQ_FIRST(&stream->queue))) {
QSIMPLEQ_REMOVE_HEAD(&stream->queue, entry);
virtio_snd_pcm_buffer_free(buffer);
diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
index 41c63b3f23b..72ef34e0976 100644
--- a/include/hw/audio/virtio-snd.h
+++ b/include/hw/audio/virtio-snd.h
@@ -75,8 +75,6 @@ typedef struct VirtIOSoundPCMStream VirtIOSoundPCMStream;
typedef struct virtio_snd_ctrl_command virtio_snd_ctrl_command;
-typedef struct VirtIOSoundPCM VirtIOSoundPCM;
-
typedef struct VirtIOSoundPCMBuffer VirtIOSoundPCMBuffer;
/*
@@ -121,31 +119,18 @@ struct VirtIOSoundPCMBuffer {
uint8_t data[];
};
-struct VirtIOSoundPCM {
- /*
- * PCM parameters are a separate field instead of a VirtIOSoundPCMStream
- * field, because the operation of PCM control requests is first
- * VIRTIO_SND_R_PCM_SET_PARAMS and then VIRTIO_SND_R_PCM_PREPARE; this
- * means that some times we get parameters without having an allocated
- * stream yet.
- */
- virtio_snd_pcm_set_params *pcm_params;
- VirtIOSoundPCMStream **streams;
-};
-
struct VirtIOSoundPCMStream {
virtio_snd_pcm_info info;
virtio_snd_pcm_set_params params;
+ uint32_t state;
/* channel position values (VIRTIO_SND_CHMAP_XXX) */
uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
VirtIOSound *s;
- bool flushing;
audsettings as;
union {
SWVoiceIn *in;
SWVoiceOut *out;
} voice;
- bool active;
uint32_t latency_bytes;
QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) queue;
};
@@ -212,7 +197,6 @@ struct VirtIOSound {
VirtQueue *queues[VIRTIO_SND_VQ_MAX];
uint64_t features;
- VirtIOSoundPCM pcm;
VirtIOSoundPCMStream *streams;
AudioBackend *audio_be;
VMChangeStateEntry *vmstate;
--
2.47.3
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v3 5/9] hw/audio/virtio-sound: add stream state variable
2026-06-26 12:35 ` [PATCH v3 5/9] hw/audio/virtio-sound: add stream state variable Alexander Mikhalitsyn
@ 2026-06-26 14:12 ` marcandre.lureau
2026-06-29 7:58 ` Manos Pitsidianakis
1 sibling, 0 replies; 26+ messages in thread
From: marcandre.lureau @ 2026-06-26 14:12 UTC (permalink / raw)
To: Alexander Mikhalitsyn
Cc: qemu-devel, Volker Rümelin, Marc-André Lureau,
Manos Pitsidianakis, Stéphane Graber,
Daniel P . Berrangé, Gerd Hoffmann, Michael S. Tsirkin,
Alexander Mikhalitsyn
> So far, only rudimentary checks have been made to ensure that
> the guest only performs state transitions permitted in
> virtio-v1.2-csd01 5.14.6.6.1 PCM Command Lifecycle. Add a state
> variable per audio stream and check all state transitions.
>
> Because only permitted state transitions are possible, only one
> copy of the audio stream parameters is required and these do not
> need to be initialised with default values.
>
> The state variable will also make it easier to restore the audio
> stream after migration.
>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
> [AM: there were too many conflicts, I did `git checkout --ours -- <.>`
> and then reimplemented the patch idea
> /AM]
> Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
> Message-ID: <20260626123531.132078-6-alexander@mihalicyn.com>
>
> diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
> index 41c63b3f23b..72ef34e0976 100644
> --- a/include/hw/audio/virtio-snd.h
> +++ b/include/hw/audio/virtio-snd.h
> @@ -75,8 +75,6 @@ typedef struct VirtIOSoundPCMStream VirtIOSoundPCMStream;
>
> typedef struct virtio_snd_ctrl_command virtio_snd_ctrl_command;
>
> -typedef struct VirtIOSoundPCM VirtIOSoundPCM;
> -
> typedef struct VirtIOSoundPCMBuffer VirtIOSoundPCMBuffer;
>
> /*
> @@ -121,31 +119,18 @@ struct VirtIOSoundPCMBuffer {
> uint8_t data[];
> };
>
> -struct VirtIOSoundPCM {
> - /*
> - * PCM parameters are a separate field instead of a VirtIOSoundPCMStream
> - * field, because the operation of PCM control requests is first
> - * VIRTIO_SND_R_PCM_SET_PARAMS and then VIRTIO_SND_R_PCM_PREPARE; this
> - * means that some times we get parameters without having an allocated
> - * stream yet.
> - */
> - virtio_snd_pcm_set_params *pcm_params;
> - VirtIOSoundPCMStream **streams;
> -};
> -
> struct VirtIOSoundPCMStream {
> virtio_snd_pcm_info info;
> virtio_snd_pcm_set_params params;
> + uint32_t state;
> /* channel position values (VIRTIO_SND_CHMAP_XXX) */
> uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
> VirtIOSound *s;
> - bool flushing;
> audsettings as;
> union {
> SWVoiceIn *in;
> SWVoiceOut *out;
> } voice;
> - bool active;
> uint32_t latency_bytes;
> QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) queue;
> };
> @@ -212,7 +197,6 @@ struct VirtIOSound {
>
> VirtQueue *queues[VIRTIO_SND_VQ_MAX];
> uint64_t features;
> - VirtIOSoundPCM pcm;
> VirtIOSoundPCMStream *streams;
> AudioBackend *audio_be;
> VMChangeStateEntry *vmstate;
> diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
> index 300ba13ffeb..68d737478f5 100644
> --- a/hw/audio/virtio-snd.c
> +++ b/hw/audio/virtio-snd.c
> @@ -30,11 +30,30 @@
> #define VIRTIO_SOUND_CHMAP_DEFAULT 0
> #define VIRTIO_SOUND_HDA_FN_NID 0
>
> +#define VSND_PCMSTREAM_STATE_F_PARAMS_SET 0x10000
> +#define VSND_PCMSTREAM_STATE_F_PREPARED 0x20000
> +#define VSND_PCMSTREAM_STATE_F_ACTIVE 0x40000
> +
> +#define VSND_PCMSTREAM_STATE_UNINITIALIZED 0
> +#define VSND_PCMSTREAM_STATE_PARAMS_SET (1 \
> + | VSND_PCMSTREAM_STATE_F_PARAMS_SET)
> +#define VSND_PCMSTREAM_STATE_PREPARED (2 \
> + | VSND_PCMSTREAM_STATE_F_PARAMS_SET \
> + | VSND_PCMSTREAM_STATE_F_PREPARED)
> +#define VSND_PCMSTREAM_STATE_STARTED (4 \
> + | VSND_PCMSTREAM_STATE_F_PARAMS_SET \
> + | VSND_PCMSTREAM_STATE_F_PREPARED \
> + | VSND_PCMSTREAM_STATE_F_ACTIVE)
> +#define VSND_PCMSTREAM_STATE_STOPPED (6 \
> + | VSND_PCMSTREAM_STATE_F_PARAMS_SET \
> + | VSND_PCMSTREAM_STATE_F_PREPARED)
> +#define VSND_PCMSTREAM_STATE_RELEASED (7 \
> + | VSND_PCMSTREAM_STATE_F_PARAMS_SET)
Hmm, those 1,2,4,6,7 values matches the spec 5.14.6.6.1 states. Ok, but worth a
comment imho.
> +
> static void virtio_snd_pcm_out_cb(void *data, int available);
> static void virtio_snd_process_cmdq(VirtIOSound *s);
> static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream);
> static void virtio_snd_pcm_in_cb(void *data, int available);
> -static void virtio_snd_unrealize(DeviceState *dev);
>
> static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8)
> | BIT(VIRTIO_SND_PCM_FMT_U8)
> @@ -129,7 +148,7 @@ static VirtIOSoundPCMStream *virtio_snd_pcm_get_stream(VirtIOSound *s,
> uint32_t stream_id)
> {
> return stream_id >= s->snd_conf.streams ? NULL :
> - s->pcm.streams[stream_id];
> + &s->streams[stream_id];
> }
>
> /*
> @@ -141,8 +160,8 @@ static VirtIOSoundPCMStream *virtio_snd_pcm_get_stream(VirtIOSound *s,
> static virtio_snd_pcm_set_params *virtio_snd_pcm_get_params(VirtIOSound *s,
> uint32_t stream_id)
> {
> - return stream_id >= s->snd_conf.streams ? NULL
> - : &s->pcm.pcm_params[stream_id];
> + return stream_id >= s->snd_conf.streams ? NULL :
> + &s->streams[stream_id].params;
> }
>
> /*
> @@ -245,11 +264,10 @@ static void virtio_snd_handle_pcm_info(VirtIOSound *s,
>
> /*
> * Set the given stream params.
> - * Called by both virtio_snd_handle_pcm_set_params and during device
> - * initialization.
> * Returns the response status code. (VIRTIO_SND_S_*).
> *
> * @s: VirtIOSound device
> + * @stream_id: stream id
> * @params: The PCM params as defined in the virtio specification
> */
> static
> @@ -257,14 +275,25 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
> uint32_t stream_id,
> virtio_snd_pcm_set_params *params)
> {
> + VirtIOSoundPCMStream *stream;
> virtio_snd_pcm_set_params *st_params;
>
> - if (stream_id >= s->snd_conf.streams || s->pcm.pcm_params == NULL) {
> + if (stream_id >= s->snd_conf.streams) {
> virtio_error(VIRTIO_DEVICE(s), "Streams have not been initialized.\n");
The error message should be updated.
> return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> }
>
> - st_params = virtio_snd_pcm_get_params(s, stream_id);
> + stream = virtio_snd_pcm_get_stream(s, stream_id);
> +
> + switch (stream->state) {
> + case VSND_PCMSTREAM_STATE_UNINITIALIZED:
> + case VSND_PCMSTREAM_STATE_PARAMS_SET:
> + case VSND_PCMSTREAM_STATE_PREPARED:
> + case VSND_PCMSTREAM_STATE_RELEASED:
> + break;
> + default:
Keep a virtio_error()?
> + return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> + }
>
> if (params->channels < 1 || params->channels > AUDIO_MAX_CHANNELS) {
> error_report("Number of channels is not supported.");
> @@ -281,6 +310,8 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
> return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
> }
>
> + st_params = virtio_snd_pcm_get_params(s, stream_id);
> +
> st_params->buffer_bytes = le32_to_cpu(params->buffer_bytes);
> st_params->period_bytes = le32_to_cpu(params->period_bytes);
> st_params->features = le32_to_cpu(params->features);
> @@ -289,6 +320,13 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
> st_params->format = params->format;
> st_params->rate = params->rate;
>
> + if (stream->state & VSND_PCMSTREAM_STATE_F_PREPARED) {
> + /* implicit VIRTIO_SND_R_PCM_RELEASE */
> + virtio_snd_pcm_flush(stream);
> + }
I'd leave a comment to explain we keep the SWVoice opened.
> +
> + stream->state = VSND_PCMSTREAM_STATE_PARAMS_SET;
> +
> return cpu_to_le32(VIRTIO_SND_S_OK);
> }
>
> @@ -398,15 +436,12 @@ static void virtio_snd_get_qemu_audsettings(audsettings *as,
> */
> static void virtio_snd_pcm_close(VirtIOSoundPCMStream *stream)
> {
> - if (stream) {
> - virtio_snd_pcm_flush(stream);
> - if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
> - audio_be_close_out(stream->s->audio_be, stream->voice.out);
> - stream->voice.out = NULL;
> - } else if (stream->info.direction == VIRTIO_SND_D_INPUT) {
> - audio_be_close_in(stream->s->audio_be, stream->voice.in);
> - stream->voice.in = NULL;
> - }
> + if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
> + audio_be_close_out(stream->s->audio_be, stream->voice.out);
> + stream->voice.out = NULL;
> + } else if (stream->info.direction == VIRTIO_SND_D_INPUT) {
> + audio_be_close_in(stream->s->audio_be, stream->voice.in);
> + stream->voice.in = NULL;
> }
> }
>
> @@ -423,32 +458,23 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
> virtio_snd_pcm_set_params *params;
> VirtIOSoundPCMStream *stream;
>
> - if (s->pcm.streams == NULL ||
> - s->pcm.pcm_params == NULL ||
> - stream_id >= s->snd_conf.streams) {
> + stream = virtio_snd_pcm_get_stream(s, stream_id);
> + if (!stream) {
> return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> }
>
> - params = virtio_snd_pcm_get_params(s, stream_id);
> - if (params == NULL) {
> + switch (stream->state) {
> + case VSND_PCMSTREAM_STATE_PARAMS_SET:
> + case VSND_PCMSTREAM_STATE_PREPARED:
> + case VSND_PCMSTREAM_STATE_RELEASED:
> + break;
> + default:
> return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> }
>
> - stream = virtio_snd_pcm_get_stream(s, stream_id);
> - if (stream == NULL) {
> - stream = &s->streams[stream_id];
> - stream->active = false;
> - stream->latency_bytes = 0;
> -
> - /*
> - * stream_id >= s->snd_conf.streams was checked before so this is
> - * in-bounds
> - */
> - s->pcm.streams[stream_id] = stream;
> - }
> + params = virtio_snd_pcm_get_params(s, stream_id);
>
> virtio_snd_get_qemu_audsettings(&as, params);
> - stream->params = *params;
>
> stream->positions[0] = VIRTIO_SND_CHMAP_FL;
> stream->positions[1] = VIRTIO_SND_CHMAP_FR;
> @@ -472,6 +498,8 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
> audio_be_set_volume_in_lr(s->audio_be, stream->voice.in, 0, 255, 255);
> }
>
> + stream->state = VSND_PCMSTREAM_STATE_PREPARED;
> +
> return cpu_to_le32(VIRTIO_SND_S_OK);
> }
>
> @@ -542,12 +570,28 @@ static uint32_t virtio_snd_pcm_start_stop(VirtIOSound *s,
> }
>
> if (start) {
> + switch (stream->state) {
> + case VSND_PCMSTREAM_STATE_PREPARED:
> + case VSND_PCMSTREAM_STATE_STOPPED:
> + break;
> + default:
> + return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> + }
> +
> trace_virtio_snd_handle_pcm_start(stream_id);
> + stream->state = VSND_PCMSTREAM_STATE_STARTED;
> } else {
> + switch (stream->state) {
> + case VSND_PCMSTREAM_STATE_STARTED:
> + break;
> + default:
> + return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> + }
> +
> trace_virtio_snd_handle_pcm_stop(stream_id);
> + stream->state = VSND_PCMSTREAM_STATE_STOPPED;
> }
>
> - stream->active = start;
> if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
> audio_be_set_active_out(s->audio_be, stream->voice.out, start);
> } else {
> @@ -641,6 +685,15 @@ static void virtio_snd_handle_pcm_release(VirtIOSound *s,
> return;
> }
>
> + switch (stream->state) {
> + case VSND_PCMSTREAM_STATE_PREPARED:
> + case VSND_PCMSTREAM_STATE_STOPPED:
> + break;
> + default:
> + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> + return;
> + }
> +
> if (virtio_snd_pcm_get_io_msgs_count(stream)) {
> /*
> * virtio-v1.2-csd01, 5.14.6.6.5.1,
> @@ -655,6 +708,8 @@ static void virtio_snd_handle_pcm_release(VirtIOSound *s,
> virtio_snd_pcm_flush(stream);
> }
Same here.
--
Marc-André Lureau <marcandre.lureau@redhat.com>
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH v3 5/9] hw/audio/virtio-sound: add stream state variable
2026-06-26 12:35 ` [PATCH v3 5/9] hw/audio/virtio-sound: add stream state variable Alexander Mikhalitsyn
2026-06-26 14:12 ` marcandre.lureau
@ 2026-06-29 7:58 ` Manos Pitsidianakis
2026-06-29 8:21 ` Michael S. Tsirkin
1 sibling, 1 reply; 26+ messages in thread
From: Manos Pitsidianakis @ 2026-06-29 7:58 UTC (permalink / raw)
To: Alexander Mikhalitsyn, qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
On Fri, 26 Jun 2026 15:35, Alexander Mikhalitsyn <alexander@mihalicyn.com> wrote:
>From: Volker Rümelin <vr_qemu@t-online.de>
>
>So far, only rudimentary checks have been made to ensure that
>the guest only performs state transitions permitted in
>virtio-v1.2-csd01 5.14.6.6.1 PCM Command Lifecycle. Add a state
>variable per audio stream and check all state transitions.
This was on purpose: 5.14.6.6.1 is not a Device Requirement / normative
statement. (In my opinion it should have been).
I do not oppose keeping the state though, I chose to do it in the Rust
implementation (vhost-device-sound) after I wrote this one as well. It
makes sense. But please update the commit message to say that this is
not about spec compliance, but simply doing a sanity check following the
PCM Command Lifecycle section.
>
>Because only permitted state transitions are possible, only one
>copy of the audio stream parameters is required and these do not
>need to be initialised with default values.
>
>The state variable will also make it easier to restore the audio
>stream after migration.
>
>Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
>[AM: there were too many conflicts, I did `git checkout --ours -- <.>`
> and then reimplemented the patch idea
>/AM]
>Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
>---
>v3:
> - explicitly call virtio_snd_pcm_close() from unrealize
> - remove a call to virtio_snd_pcm_flush() from virtio_snd_pcm_close()
> [ ^ this was my rebase mistake ]
>---
> hw/audio/virtio-snd.c | 196 +++++++++++++++++++---------------
> include/hw/audio/virtio-snd.h | 18 +---
> 2 files changed, 109 insertions(+), 105 deletions(-)
>
>diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
>index 300ba13ffeb..68d737478f5 100644
>--- a/hw/audio/virtio-snd.c
>+++ b/hw/audio/virtio-snd.c
>@@ -30,11 +30,30 @@
> #define VIRTIO_SOUND_CHMAP_DEFAULT 0
> #define VIRTIO_SOUND_HDA_FN_NID 0
>
>+#define VSND_PCMSTREAM_STATE_F_PARAMS_SET 0x10000
>+#define VSND_PCMSTREAM_STATE_F_PREPARED 0x20000
>+#define VSND_PCMSTREAM_STATE_F_ACTIVE 0x40000
>+
>+#define VSND_PCMSTREAM_STATE_UNINITIALIZED 0
>+#define VSND_PCMSTREAM_STATE_PARAMS_SET (1 \
>+ | VSND_PCMSTREAM_STATE_F_PARAMS_SET)
>+#define VSND_PCMSTREAM_STATE_PREPARED (2 \
>+ | VSND_PCMSTREAM_STATE_F_PARAMS_SET \
>+ | VSND_PCMSTREAM_STATE_F_PREPARED)
>+#define VSND_PCMSTREAM_STATE_STARTED (4 \
>+ | VSND_PCMSTREAM_STATE_F_PARAMS_SET \
>+ | VSND_PCMSTREAM_STATE_F_PREPARED \
>+ | VSND_PCMSTREAM_STATE_F_ACTIVE)
>+#define VSND_PCMSTREAM_STATE_STOPPED (6 \
>+ | VSND_PCMSTREAM_STATE_F_PARAMS_SET \
>+ | VSND_PCMSTREAM_STATE_F_PREPARED)
>+#define VSND_PCMSTREAM_STATE_RELEASED (7 \
>+ | VSND_PCMSTREAM_STATE_F_PARAMS_SET)
Are the VSND_PCMSTREAM_STATE_F_* really needed? Seems excessive.
I'd do: (did not type check/compile)
+ enum virtio_snd_pcm_state {
+ VIRTIO_SND_PCM_STATE_UNINIT = 0,
+ VIRTIO_SND_PCM_STATE_PARAMS_SET,
+ VIRTIO_SND_PCM_STATE_PREPARED,
+ VIRTIO_SND_PCM_STATE_STARTED,
+ VIRTIO_SND_PCM_STATE_STOPPED,
+ VIRTIO_SND_PCM_STATE_RELEASED,
+ }
Maybe even write a "method" "macro" for preparedness:
+
+ static inline bool virtio_snd_pcm_state_prepared(virtio_snd_pcm_state
s) {
+ return s > VIRTIO_SND_PCM_STATE_PARAMS_SET && s <
VIRTIO_SND_PCM_STATE_RELEASED
+ }
And "active" flag bit is only in STARTED state, so just check for
equality.
This is not a hard request, but it seems simpler to me and would prefer
it.
>+
> static void virtio_snd_pcm_out_cb(void *data, int available);
> static void virtio_snd_process_cmdq(VirtIOSound *s);
> static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream);
> static void virtio_snd_pcm_in_cb(void *data, int available);
>-static void virtio_snd_unrealize(DeviceState *dev);
>
> static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8)
> | BIT(VIRTIO_SND_PCM_FMT_U8)
>@@ -129,7 +148,7 @@ static VirtIOSoundPCMStream *virtio_snd_pcm_get_stream(VirtIOSound *s,
> uint32_t stream_id)
> {
> return stream_id >= s->snd_conf.streams ? NULL :
>- s->pcm.streams[stream_id];
>+ &s->streams[stream_id];
> }
>
> /*
>@@ -141,8 +160,8 @@ static VirtIOSoundPCMStream *virtio_snd_pcm_get_stream(VirtIOSound *s,
> static virtio_snd_pcm_set_params *virtio_snd_pcm_get_params(VirtIOSound *s,
> uint32_t stream_id)
> {
>- return stream_id >= s->snd_conf.streams ? NULL
>- : &s->pcm.pcm_params[stream_id];
>+ return stream_id >= s->snd_conf.streams ? NULL :
>+ &s->streams[stream_id].params;
> }
>
> /*
>@@ -245,11 +264,10 @@ static void virtio_snd_handle_pcm_info(VirtIOSound *s,
>
> /*
> * Set the given stream params.
>- * Called by both virtio_snd_handle_pcm_set_params and during device
>- * initialization.
> * Returns the response status code. (VIRTIO_SND_S_*).
> *
> * @s: VirtIOSound device
>+ * @stream_id: stream id
> * @params: The PCM params as defined in the virtio specification
> */
> static
>@@ -257,14 +275,25 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
> uint32_t stream_id,
> virtio_snd_pcm_set_params *params)
> {
>+ VirtIOSoundPCMStream *stream;
> virtio_snd_pcm_set_params *st_params;
>
>- if (stream_id >= s->snd_conf.streams || s->pcm.pcm_params == NULL) {
>+ if (stream_id >= s->snd_conf.streams) {
> virtio_error(VIRTIO_DEVICE(s), "Streams have not been initialized.\n");
> return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> }
>
>- st_params = virtio_snd_pcm_get_params(s, stream_id);
>+ stream = virtio_snd_pcm_get_stream(s, stream_id);
>+
>+ switch (stream->state) {
>+ case VSND_PCMSTREAM_STATE_UNINITIALIZED:
>+ case VSND_PCMSTREAM_STATE_PARAMS_SET:
>+ case VSND_PCMSTREAM_STATE_PREPARED:
>+ case VSND_PCMSTREAM_STATE_RELEASED:
>+ break;
>+ default:
>+ return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
>+ }
>
> if (params->channels < 1 || params->channels > AUDIO_MAX_CHANNELS) {
> error_report("Number of channels is not supported.");
>@@ -281,6 +310,8 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
> return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
> }
>
>+ st_params = virtio_snd_pcm_get_params(s, stream_id);
>+
> st_params->buffer_bytes = le32_to_cpu(params->buffer_bytes);
> st_params->period_bytes = le32_to_cpu(params->period_bytes);
> st_params->features = le32_to_cpu(params->features);
>@@ -289,6 +320,13 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
> st_params->format = params->format;
> st_params->rate = params->rate;
>
>+ if (stream->state & VSND_PCMSTREAM_STATE_F_PREPARED) {
>+ /* implicit VIRTIO_SND_R_PCM_RELEASE */
>+ virtio_snd_pcm_flush(stream);
>+ }
>+
>+ stream->state = VSND_PCMSTREAM_STATE_PARAMS_SET;
>+
> return cpu_to_le32(VIRTIO_SND_S_OK);
> }
>
>@@ -398,15 +436,12 @@ static void virtio_snd_get_qemu_audsettings(audsettings *as,
> */
> static void virtio_snd_pcm_close(VirtIOSoundPCMStream *stream)
> {
>- if (stream) {
>- virtio_snd_pcm_flush(stream);
>- if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
>- audio_be_close_out(stream->s->audio_be, stream->voice.out);
>- stream->voice.out = NULL;
>- } else if (stream->info.direction == VIRTIO_SND_D_INPUT) {
>- audio_be_close_in(stream->s->audio_be, stream->voice.in);
>- stream->voice.in = NULL;
>- }
>+ if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
>+ audio_be_close_out(stream->s->audio_be, stream->voice.out);
>+ stream->voice.out = NULL;
>+ } else if (stream->info.direction == VIRTIO_SND_D_INPUT) {
>+ audio_be_close_in(stream->s->audio_be, stream->voice.in);
>+ stream->voice.in = NULL;
> }
> }
>
>@@ -423,32 +458,23 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
> virtio_snd_pcm_set_params *params;
> VirtIOSoundPCMStream *stream;
>
>- if (s->pcm.streams == NULL ||
>- s->pcm.pcm_params == NULL ||
>- stream_id >= s->snd_conf.streams) {
>+ stream = virtio_snd_pcm_get_stream(s, stream_id);
>+ if (!stream) {
> return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> }
>
>- params = virtio_snd_pcm_get_params(s, stream_id);
>- if (params == NULL) {
>+ switch (stream->state) {
>+ case VSND_PCMSTREAM_STATE_PARAMS_SET:
>+ case VSND_PCMSTREAM_STATE_PREPARED:
>+ case VSND_PCMSTREAM_STATE_RELEASED:
>+ break;
>+ default:
> return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> }
>
>- stream = virtio_snd_pcm_get_stream(s, stream_id);
>- if (stream == NULL) {
>- stream = &s->streams[stream_id];
>- stream->active = false;
>- stream->latency_bytes = 0;
>-
>- /*
>- * stream_id >= s->snd_conf.streams was checked before so this is
>- * in-bounds
>- */
>- s->pcm.streams[stream_id] = stream;
>- }
>+ params = virtio_snd_pcm_get_params(s, stream_id);
>
> virtio_snd_get_qemu_audsettings(&as, params);
>- stream->params = *params;
>
> stream->positions[0] = VIRTIO_SND_CHMAP_FL;
> stream->positions[1] = VIRTIO_SND_CHMAP_FR;
>@@ -472,6 +498,8 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
> audio_be_set_volume_in_lr(s->audio_be, stream->voice.in, 0, 255, 255);
> }
>
>+ stream->state = VSND_PCMSTREAM_STATE_PREPARED;
>+
> return cpu_to_le32(VIRTIO_SND_S_OK);
> }
>
>@@ -542,12 +570,28 @@ static uint32_t virtio_snd_pcm_start_stop(VirtIOSound *s,
> }
>
> if (start) {
>+ switch (stream->state) {
>+ case VSND_PCMSTREAM_STATE_PREPARED:
>+ case VSND_PCMSTREAM_STATE_STOPPED:
>+ break;
>+ default:
>+ return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
>+ }
>+
> trace_virtio_snd_handle_pcm_start(stream_id);
>+ stream->state = VSND_PCMSTREAM_STATE_STARTED;
> } else {
>+ switch (stream->state) {
>+ case VSND_PCMSTREAM_STATE_STARTED:
>+ break;
>+ default:
>+ return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
>+ }
>+
> trace_virtio_snd_handle_pcm_stop(stream_id);
>+ stream->state = VSND_PCMSTREAM_STATE_STOPPED;
> }
>
>- stream->active = start;
> if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
> audio_be_set_active_out(s->audio_be, stream->voice.out, start);
> } else {
>@@ -641,6 +685,15 @@ static void virtio_snd_handle_pcm_release(VirtIOSound *s,
> return;
> }
>
>+ switch (stream->state) {
>+ case VSND_PCMSTREAM_STATE_PREPARED:
>+ case VSND_PCMSTREAM_STATE_STOPPED:
>+ break;
>+ default:
>+ cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
>+ return;
>+ }
>+
> if (virtio_snd_pcm_get_io_msgs_count(stream)) {
> /*
> * virtio-v1.2-csd01, 5.14.6.6.5.1,
>@@ -655,6 +708,8 @@ static void virtio_snd_handle_pcm_release(VirtIOSound *s,
> virtio_snd_pcm_flush(stream);
> }
>
>+ stream->state = VSND_PCMSTREAM_STATE_RELEASED;
>+
> cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
> }
>
>@@ -876,12 +931,11 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
> }
> stream_id = le32_to_cpu(hdr.stream_id);
>
>- if (stream_id >= vsnd->snd_conf.streams
>- || vsnd->pcm.streams[stream_id] == NULL) {
>+ if (stream_id >= vsnd->snd_conf.streams) {
> goto tx_err;
> }
>
>- stream = vsnd->pcm.streams[stream_id];
>+ stream = &vsnd->streams[stream_id];
> if (stream->info.direction != VIRTIO_SND_D_OUTPUT) {
> goto tx_err;
> }
>@@ -956,13 +1010,12 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
> }
> stream_id = le32_to_cpu(hdr.stream_id);
>
>- if (stream_id >= vsnd->snd_conf.streams
>- || !vsnd->pcm.streams[stream_id]) {
>+ if (stream_id >= vsnd->snd_conf.streams) {
> goto rx_err;
> }
>
>- stream = vsnd->pcm.streams[stream_id];
>- if (stream == NULL || stream->info.direction != VIRTIO_SND_D_INPUT) {
>+ stream = &vsnd->streams[stream_id];
>+ if (stream->info.direction != VIRTIO_SND_D_INPUT) {
> goto rx_err;
> }
>
>@@ -1021,8 +1074,6 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
> ERRP_GUARD();
> VirtIOSound *vsnd = VIRTIO_SND(dev);
> VirtIODevice *vdev = VIRTIO_DEVICE(dev);
>- virtio_snd_pcm_set_params default_params = { 0 };
>- uint32_t status;
>
> trace_virtio_snd_realize(vsnd);
>
>@@ -1059,6 +1110,7 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
> for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
> VirtIOSoundPCMStream *stream = &vsnd->streams[i];
>
>+ stream->state = VSND_PCMSTREAM_STATE_UNINITIALIZED;
> stream->s = vsnd;
> QSIMPLEQ_INIT(&stream->queue);
> stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID;
>@@ -1072,21 +1124,9 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
> stream->info.channels_max = 2;
> }
>
>- vsnd->pcm.streams =
>- g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams);
>- vsnd->pcm.pcm_params =
>- g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams);
>-
> virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config));
> virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1);
>
>- /* set default params for all streams */
>- default_params.features = 0;
>- default_params.buffer_bytes = cpu_to_le32(8192);
>- default_params.period_bytes = cpu_to_le32(2048);
>- default_params.channels = 2;
>- default_params.format = VIRTIO_SND_PCM_FMT_S16;
>- default_params.rate = VIRTIO_SND_PCM_RATE_48000;
> vsnd->queues[VIRTIO_SND_VQ_CONTROL] =
> virtio_add_queue(vdev, 64, virtio_snd_handle_ctrl);
> vsnd->queues[VIRTIO_SND_VQ_EVENT] =
>@@ -1097,28 +1137,6 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
> virtio_add_queue(vdev, 64, virtio_snd_handle_rx_xfer);
> QTAILQ_INIT(&vsnd->cmdq);
> QSIMPLEQ_INIT(&vsnd->invalid);
>-
>- for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
>- status = virtio_snd_set_pcm_params(vsnd, i, &default_params);
>- if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
>- error_setg(errp,
>- "Can't initialize stream params, device responded with %s.",
>- print_code(status));
>- goto error_cleanup;
>- }
>- status = virtio_snd_pcm_prepare(vsnd, i);
>- if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
>- error_setg(errp,
>- "Can't prepare streams, device responded with %s.",
>- print_code(status));
>- goto error_cleanup;
>- }
>- }
>-
>- return;
>-
>-error_cleanup:
>- virtio_snd_unrealize(dev);
> }
>
> static inline void update_latency(VirtIOSoundPCMStream *s, size_t used)
>@@ -1167,7 +1185,7 @@ static void virtio_snd_pcm_out_cb(void *data, int available)
> if (!virtio_queue_ready(buffer->vq)) {
> return;
> }
>- if (!stream->active) {
>+ if (!(stream->state & VSND_PCMSTREAM_STATE_F_ACTIVE)) {
> /* Stream has stopped, so do not perform audio_be_write. */
> return_tx_buffer(stream, buffer);
> continue;
>@@ -1261,7 +1279,7 @@ static void virtio_snd_pcm_in_cb(void *data, int available)
> if (!virtio_queue_ready(buffer->vq)) {
> return;
> }
>- if (!stream->active) {
>+ if (!(stream->state & VSND_PCMSTREAM_STATE_F_ACTIVE)) {
> /* Stream has stopped, so do not perform audio_be_read. */
> return_rx_buffer(stream, buffer);
> continue;
>@@ -1334,17 +1352,16 @@ static void virtio_snd_unrealize(DeviceState *dev)
> qemu_del_vm_change_state_handler(vsnd->vmstate);
> trace_virtio_snd_unrealize(vsnd);
>
>- if (vsnd->pcm.streams) {
>+ if (vsnd->streams) {
>+ virtio_snd_process_cmdq(vsnd);
> for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
>- stream = vsnd->pcm.streams[i];
>- if (stream) {
>- virtio_snd_process_cmdq(stream->s);
>- virtio_snd_pcm_close(stream);
>+ stream = &vsnd->streams[i];
>+ if (stream->state & VSND_PCMSTREAM_STATE_F_PREPARED) {
>+ virtio_snd_pcm_flush(stream);
> }
>+ virtio_snd_pcm_close(stream);
> }
>- g_free(vsnd->pcm.streams);
> }
>- g_free(vsnd->pcm.pcm_params);
> g_free(vsnd->streams);
> vsnd->streams = NULL;
> virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]);
>@@ -1378,6 +1395,9 @@ static void virtio_snd_reset(VirtIODevice *vdev)
> VirtIOSoundPCMStream *stream = &vsnd->streams[i];
> VirtIOSoundPCMBuffer *buffer;
>
>+ virtio_snd_pcm_close(stream);
>+ stream->state = VSND_PCMSTREAM_STATE_UNINITIALIZED;
>+
> while ((buffer = QSIMPLEQ_FIRST(&stream->queue))) {
> QSIMPLEQ_REMOVE_HEAD(&stream->queue, entry);
> virtio_snd_pcm_buffer_free(buffer);
>diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
>index 41c63b3f23b..72ef34e0976 100644
>--- a/include/hw/audio/virtio-snd.h
>+++ b/include/hw/audio/virtio-snd.h
>@@ -75,8 +75,6 @@ typedef struct VirtIOSoundPCMStream VirtIOSoundPCMStream;
>
> typedef struct virtio_snd_ctrl_command virtio_snd_ctrl_command;
>
>-typedef struct VirtIOSoundPCM VirtIOSoundPCM;
>-
> typedef struct VirtIOSoundPCMBuffer VirtIOSoundPCMBuffer;
>
> /*
>@@ -121,31 +119,18 @@ struct VirtIOSoundPCMBuffer {
> uint8_t data[];
> };
>
>-struct VirtIOSoundPCM {
>- /*
>- * PCM parameters are a separate field instead of a VirtIOSoundPCMStream
>- * field, because the operation of PCM control requests is first
>- * VIRTIO_SND_R_PCM_SET_PARAMS and then VIRTIO_SND_R_PCM_PREPARE; this
>- * means that some times we get parameters without having an allocated
>- * stream yet.
>- */
>- virtio_snd_pcm_set_params *pcm_params;
>- VirtIOSoundPCMStream **streams;
>-};
>-
> struct VirtIOSoundPCMStream {
> virtio_snd_pcm_info info;
> virtio_snd_pcm_set_params params;
>+ uint32_t state;
> /* channel position values (VIRTIO_SND_CHMAP_XXX) */
> uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
> VirtIOSound *s;
>- bool flushing;
Spurious change: this should be a separate patch.
> audsettings as;
> union {
> SWVoiceIn *in;
> SWVoiceOut *out;
> } voice;
>- bool active;
> uint32_t latency_bytes;
> QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) queue;
> };
>@@ -212,7 +197,6 @@ struct VirtIOSound {
>
> VirtQueue *queues[VIRTIO_SND_VQ_MAX];
> uint64_t features;
>- VirtIOSoundPCM pcm;
> VirtIOSoundPCMStream *streams;
> AudioBackend *audio_be;
> VMChangeStateEntry *vmstate;
>--
>2.47.3
>
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH v3 5/9] hw/audio/virtio-sound: add stream state variable
2026-06-29 7:58 ` Manos Pitsidianakis
@ 2026-06-29 8:21 ` Michael S. Tsirkin
2026-06-29 8:31 ` Manos Pitsidianakis
0 siblings, 1 reply; 26+ messages in thread
From: Michael S. Tsirkin @ 2026-06-29 8:21 UTC (permalink / raw)
To: Manos Pitsidianakis
Cc: Alexander Mikhalitsyn, qemu-devel, Volker Rümelin,
Marc-André Lureau, Stéphane Graber,
Daniel P . Berrangé, Gerd Hoffmann, Alexander Mikhalitsyn
On Mon, Jun 29, 2026 at 10:58:32AM +0300, Manos Pitsidianakis wrote:
> On Fri, 26 Jun 2026 15:35, Alexander Mikhalitsyn <alexander@mihalicyn.com> wrote:
> > From: Volker Rümelin <vr_qemu@t-online.de>
> >
> > So far, only rudimentary checks have been made to ensure that
> > the guest only performs state transitions permitted in
> > virtio-v1.2-csd01 5.14.6.6.1 PCM Command Lifecycle. Add a state
> > variable per audio stream and check all state transitions.
>
>
> This was on purpose: 5.14.6.6.1 is not a Device Requirement / normative
> statement. (In my opinion it should have been).
It's easy to add them - even strong ones (MUST) if it's clear from the description that this
was always the intent, and no reasonable implementation would
do anything else.
If not we can add weak ones (SHOULD).
> I do not oppose keeping the state though, I chose to do it in the Rust
> implementation (vhost-device-sound) after I wrote this one as well. It makes
> sense. But please update the commit message to say that this is not about
> spec compliance, but simply doing a sanity check following the PCM Command
> Lifecycle section.
>
>
> >
> > Because only permitted state transitions are possible, only one
> > copy of the audio stream parameters is required and these do not
> > need to be initialised with default values.
> >
> > The state variable will also make it easier to restore the audio
> > stream after migration.
> >
> > Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
> > [AM: there were too many conflicts, I did `git checkout --ours -- <.>`
> > and then reimplemented the patch idea
> > /AM]
> > Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
> > ---
> > v3:
> > - explicitly call virtio_snd_pcm_close() from unrealize
> > - remove a call to virtio_snd_pcm_flush() from virtio_snd_pcm_close()
> > [ ^ this was my rebase mistake ]
> > ---
> > hw/audio/virtio-snd.c | 196 +++++++++++++++++++---------------
> > include/hw/audio/virtio-snd.h | 18 +---
> > 2 files changed, 109 insertions(+), 105 deletions(-)
> >
> > diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
> > index 300ba13ffeb..68d737478f5 100644
> > --- a/hw/audio/virtio-snd.c
> > +++ b/hw/audio/virtio-snd.c
> > @@ -30,11 +30,30 @@
> > #define VIRTIO_SOUND_CHMAP_DEFAULT 0
> > #define VIRTIO_SOUND_HDA_FN_NID 0
> >
> > +#define VSND_PCMSTREAM_STATE_F_PARAMS_SET 0x10000
> > +#define VSND_PCMSTREAM_STATE_F_PREPARED 0x20000
> > +#define VSND_PCMSTREAM_STATE_F_ACTIVE 0x40000
> > +
> > +#define VSND_PCMSTREAM_STATE_UNINITIALIZED 0
> > +#define VSND_PCMSTREAM_STATE_PARAMS_SET (1 \
> > + | VSND_PCMSTREAM_STATE_F_PARAMS_SET)
> > +#define VSND_PCMSTREAM_STATE_PREPARED (2 \
> > + | VSND_PCMSTREAM_STATE_F_PARAMS_SET \
> > + | VSND_PCMSTREAM_STATE_F_PREPARED)
> > +#define VSND_PCMSTREAM_STATE_STARTED (4 \
> > + | VSND_PCMSTREAM_STATE_F_PARAMS_SET \
> > + | VSND_PCMSTREAM_STATE_F_PREPARED \
> > + | VSND_PCMSTREAM_STATE_F_ACTIVE)
> > +#define VSND_PCMSTREAM_STATE_STOPPED (6 \
> > + | VSND_PCMSTREAM_STATE_F_PARAMS_SET \
> > + | VSND_PCMSTREAM_STATE_F_PREPARED)
> > +#define VSND_PCMSTREAM_STATE_RELEASED (7 \
> > + | VSND_PCMSTREAM_STATE_F_PARAMS_SET)
>
> Are the VSND_PCMSTREAM_STATE_F_* really needed? Seems excessive.
>
> I'd do: (did not type check/compile)
>
> + enum virtio_snd_pcm_state {
> + VIRTIO_SND_PCM_STATE_UNINIT = 0,
> + VIRTIO_SND_PCM_STATE_PARAMS_SET,
> + VIRTIO_SND_PCM_STATE_PREPARED,
> + VIRTIO_SND_PCM_STATE_STARTED,
> + VIRTIO_SND_PCM_STATE_STOPPED,
> + VIRTIO_SND_PCM_STATE_RELEASED,
> + }
>
> Maybe even write a "method" "macro" for preparedness:
>
> +
> + static inline bool virtio_snd_pcm_state_prepared(virtio_snd_pcm_state s) {
> + return s > VIRTIO_SND_PCM_STATE_PARAMS_SET && s <
> VIRTIO_SND_PCM_STATE_RELEASED
> + }
>
> And "active" flag bit is only in STARTED state, so just check for equality.
>
> This is not a hard request, but it seems simpler to me and would prefer it.
>
> > +
> > static void virtio_snd_pcm_out_cb(void *data, int available);
> > static void virtio_snd_process_cmdq(VirtIOSound *s);
> > static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream);
> > static void virtio_snd_pcm_in_cb(void *data, int available);
> > -static void virtio_snd_unrealize(DeviceState *dev);
> >
> > static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8)
> > | BIT(VIRTIO_SND_PCM_FMT_U8)
> > @@ -129,7 +148,7 @@ static VirtIOSoundPCMStream *virtio_snd_pcm_get_stream(VirtIOSound *s,
> > uint32_t stream_id)
> > {
> > return stream_id >= s->snd_conf.streams ? NULL :
> > - s->pcm.streams[stream_id];
> > + &s->streams[stream_id];
> > }
> >
> > /*
> > @@ -141,8 +160,8 @@ static VirtIOSoundPCMStream *virtio_snd_pcm_get_stream(VirtIOSound *s,
> > static virtio_snd_pcm_set_params *virtio_snd_pcm_get_params(VirtIOSound *s,
> > uint32_t stream_id)
> > {
> > - return stream_id >= s->snd_conf.streams ? NULL
> > - : &s->pcm.pcm_params[stream_id];
> > + return stream_id >= s->snd_conf.streams ? NULL :
> > + &s->streams[stream_id].params;
> > }
> >
> > /*
> > @@ -245,11 +264,10 @@ static void virtio_snd_handle_pcm_info(VirtIOSound *s,
> >
> > /*
> > * Set the given stream params.
> > - * Called by both virtio_snd_handle_pcm_set_params and during device
> > - * initialization.
> > * Returns the response status code. (VIRTIO_SND_S_*).
> > *
> > * @s: VirtIOSound device
> > + * @stream_id: stream id
> > * @params: The PCM params as defined in the virtio specification
> > */
> > static
> > @@ -257,14 +275,25 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
> > uint32_t stream_id,
> > virtio_snd_pcm_set_params *params)
> > {
> > + VirtIOSoundPCMStream *stream;
> > virtio_snd_pcm_set_params *st_params;
> >
> > - if (stream_id >= s->snd_conf.streams || s->pcm.pcm_params == NULL) {
> > + if (stream_id >= s->snd_conf.streams) {
> > virtio_error(VIRTIO_DEVICE(s), "Streams have not been initialized.\n");
> > return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> > }
> >
> > - st_params = virtio_snd_pcm_get_params(s, stream_id);
> > + stream = virtio_snd_pcm_get_stream(s, stream_id);
> > +
> > + switch (stream->state) {
> > + case VSND_PCMSTREAM_STATE_UNINITIALIZED:
> > + case VSND_PCMSTREAM_STATE_PARAMS_SET:
> > + case VSND_PCMSTREAM_STATE_PREPARED:
> > + case VSND_PCMSTREAM_STATE_RELEASED:
> > + break;
> > + default:
> > + return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> > + }
> >
> > if (params->channels < 1 || params->channels > AUDIO_MAX_CHANNELS) {
> > error_report("Number of channels is not supported.");
> > @@ -281,6 +310,8 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
> > return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
> > }
> >
> > + st_params = virtio_snd_pcm_get_params(s, stream_id);
> > +
> > st_params->buffer_bytes = le32_to_cpu(params->buffer_bytes);
> > st_params->period_bytes = le32_to_cpu(params->period_bytes);
> > st_params->features = le32_to_cpu(params->features);
> > @@ -289,6 +320,13 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
> > st_params->format = params->format;
> > st_params->rate = params->rate;
> >
> > + if (stream->state & VSND_PCMSTREAM_STATE_F_PREPARED) {
> > + /* implicit VIRTIO_SND_R_PCM_RELEASE */
> > + virtio_snd_pcm_flush(stream);
> > + }
> > +
> > + stream->state = VSND_PCMSTREAM_STATE_PARAMS_SET;
> > +
> > return cpu_to_le32(VIRTIO_SND_S_OK);
> > }
> >
> > @@ -398,15 +436,12 @@ static void virtio_snd_get_qemu_audsettings(audsettings *as,
> > */
> > static void virtio_snd_pcm_close(VirtIOSoundPCMStream *stream)
> > {
> > - if (stream) {
> > - virtio_snd_pcm_flush(stream);
> > - if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
> > - audio_be_close_out(stream->s->audio_be, stream->voice.out);
> > - stream->voice.out = NULL;
> > - } else if (stream->info.direction == VIRTIO_SND_D_INPUT) {
> > - audio_be_close_in(stream->s->audio_be, stream->voice.in);
> > - stream->voice.in = NULL;
> > - }
> > + if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
> > + audio_be_close_out(stream->s->audio_be, stream->voice.out);
> > + stream->voice.out = NULL;
> > + } else if (stream->info.direction == VIRTIO_SND_D_INPUT) {
> > + audio_be_close_in(stream->s->audio_be, stream->voice.in);
> > + stream->voice.in = NULL;
> > }
> > }
> >
> > @@ -423,32 +458,23 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
> > virtio_snd_pcm_set_params *params;
> > VirtIOSoundPCMStream *stream;
> >
> > - if (s->pcm.streams == NULL ||
> > - s->pcm.pcm_params == NULL ||
> > - stream_id >= s->snd_conf.streams) {
> > + stream = virtio_snd_pcm_get_stream(s, stream_id);
> > + if (!stream) {
> > return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> > }
> >
> > - params = virtio_snd_pcm_get_params(s, stream_id);
> > - if (params == NULL) {
> > + switch (stream->state) {
> > + case VSND_PCMSTREAM_STATE_PARAMS_SET:
> > + case VSND_PCMSTREAM_STATE_PREPARED:
> > + case VSND_PCMSTREAM_STATE_RELEASED:
> > + break;
> > + default:
> > return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> > }
> >
> > - stream = virtio_snd_pcm_get_stream(s, stream_id);
> > - if (stream == NULL) {
> > - stream = &s->streams[stream_id];
> > - stream->active = false;
> > - stream->latency_bytes = 0;
> > -
> > - /*
> > - * stream_id >= s->snd_conf.streams was checked before so this is
> > - * in-bounds
> > - */
> > - s->pcm.streams[stream_id] = stream;
> > - }
> > + params = virtio_snd_pcm_get_params(s, stream_id);
> >
> > virtio_snd_get_qemu_audsettings(&as, params);
> > - stream->params = *params;
> >
> > stream->positions[0] = VIRTIO_SND_CHMAP_FL;
> > stream->positions[1] = VIRTIO_SND_CHMAP_FR;
> > @@ -472,6 +498,8 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
> > audio_be_set_volume_in_lr(s->audio_be, stream->voice.in, 0, 255, 255);
> > }
> >
> > + stream->state = VSND_PCMSTREAM_STATE_PREPARED;
> > +
> > return cpu_to_le32(VIRTIO_SND_S_OK);
> > }
> >
> > @@ -542,12 +570,28 @@ static uint32_t virtio_snd_pcm_start_stop(VirtIOSound *s,
> > }
> >
> > if (start) {
> > + switch (stream->state) {
> > + case VSND_PCMSTREAM_STATE_PREPARED:
> > + case VSND_PCMSTREAM_STATE_STOPPED:
> > + break;
> > + default:
> > + return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> > + }
> > +
> > trace_virtio_snd_handle_pcm_start(stream_id);
> > + stream->state = VSND_PCMSTREAM_STATE_STARTED;
> > } else {
> > + switch (stream->state) {
> > + case VSND_PCMSTREAM_STATE_STARTED:
> > + break;
> > + default:
> > + return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> > + }
> > +
> > trace_virtio_snd_handle_pcm_stop(stream_id);
> > + stream->state = VSND_PCMSTREAM_STATE_STOPPED;
> > }
> >
> > - stream->active = start;
> > if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
> > audio_be_set_active_out(s->audio_be, stream->voice.out, start);
> > } else {
> > @@ -641,6 +685,15 @@ static void virtio_snd_handle_pcm_release(VirtIOSound *s,
> > return;
> > }
> >
> > + switch (stream->state) {
> > + case VSND_PCMSTREAM_STATE_PREPARED:
> > + case VSND_PCMSTREAM_STATE_STOPPED:
> > + break;
> > + default:
> > + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> > + return;
> > + }
> > +
> > if (virtio_snd_pcm_get_io_msgs_count(stream)) {
> > /*
> > * virtio-v1.2-csd01, 5.14.6.6.5.1,
> > @@ -655,6 +708,8 @@ static void virtio_snd_handle_pcm_release(VirtIOSound *s,
> > virtio_snd_pcm_flush(stream);
> > }
> >
> > + stream->state = VSND_PCMSTREAM_STATE_RELEASED;
> > +
> > cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
> > }
> >
> > @@ -876,12 +931,11 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
> > }
> > stream_id = le32_to_cpu(hdr.stream_id);
> >
> > - if (stream_id >= vsnd->snd_conf.streams
> > - || vsnd->pcm.streams[stream_id] == NULL) {
> > + if (stream_id >= vsnd->snd_conf.streams) {
> > goto tx_err;
> > }
> >
> > - stream = vsnd->pcm.streams[stream_id];
> > + stream = &vsnd->streams[stream_id];
> > if (stream->info.direction != VIRTIO_SND_D_OUTPUT) {
> > goto tx_err;
> > }
> > @@ -956,13 +1010,12 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
> > }
> > stream_id = le32_to_cpu(hdr.stream_id);
> >
> > - if (stream_id >= vsnd->snd_conf.streams
> > - || !vsnd->pcm.streams[stream_id]) {
> > + if (stream_id >= vsnd->snd_conf.streams) {
> > goto rx_err;
> > }
> >
> > - stream = vsnd->pcm.streams[stream_id];
> > - if (stream == NULL || stream->info.direction != VIRTIO_SND_D_INPUT) {
> > + stream = &vsnd->streams[stream_id];
> > + if (stream->info.direction != VIRTIO_SND_D_INPUT) {
> > goto rx_err;
> > }
> >
> > @@ -1021,8 +1074,6 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
> > ERRP_GUARD();
> > VirtIOSound *vsnd = VIRTIO_SND(dev);
> > VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> > - virtio_snd_pcm_set_params default_params = { 0 };
> > - uint32_t status;
> >
> > trace_virtio_snd_realize(vsnd);
> >
> > @@ -1059,6 +1110,7 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
> > for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
> > VirtIOSoundPCMStream *stream = &vsnd->streams[i];
> >
> > + stream->state = VSND_PCMSTREAM_STATE_UNINITIALIZED;
> > stream->s = vsnd;
> > QSIMPLEQ_INIT(&stream->queue);
> > stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID;
> > @@ -1072,21 +1124,9 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
> > stream->info.channels_max = 2;
> > }
> >
> > - vsnd->pcm.streams =
> > - g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams);
> > - vsnd->pcm.pcm_params =
> > - g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams);
> > -
> > virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config));
> > virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1);
> >
> > - /* set default params for all streams */
> > - default_params.features = 0;
> > - default_params.buffer_bytes = cpu_to_le32(8192);
> > - default_params.period_bytes = cpu_to_le32(2048);
> > - default_params.channels = 2;
> > - default_params.format = VIRTIO_SND_PCM_FMT_S16;
> > - default_params.rate = VIRTIO_SND_PCM_RATE_48000;
> > vsnd->queues[VIRTIO_SND_VQ_CONTROL] =
> > virtio_add_queue(vdev, 64, virtio_snd_handle_ctrl);
> > vsnd->queues[VIRTIO_SND_VQ_EVENT] =
> > @@ -1097,28 +1137,6 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
> > virtio_add_queue(vdev, 64, virtio_snd_handle_rx_xfer);
> > QTAILQ_INIT(&vsnd->cmdq);
> > QSIMPLEQ_INIT(&vsnd->invalid);
> > -
> > - for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
> > - status = virtio_snd_set_pcm_params(vsnd, i, &default_params);
> > - if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
> > - error_setg(errp,
> > - "Can't initialize stream params, device responded with %s.",
> > - print_code(status));
> > - goto error_cleanup;
> > - }
> > - status = virtio_snd_pcm_prepare(vsnd, i);
> > - if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
> > - error_setg(errp,
> > - "Can't prepare streams, device responded with %s.",
> > - print_code(status));
> > - goto error_cleanup;
> > - }
> > - }
> > -
> > - return;
> > -
> > -error_cleanup:
> > - virtio_snd_unrealize(dev);
> > }
> >
> > static inline void update_latency(VirtIOSoundPCMStream *s, size_t used)
> > @@ -1167,7 +1185,7 @@ static void virtio_snd_pcm_out_cb(void *data, int available)
> > if (!virtio_queue_ready(buffer->vq)) {
> > return;
> > }
> > - if (!stream->active) {
> > + if (!(stream->state & VSND_PCMSTREAM_STATE_F_ACTIVE)) {
> > /* Stream has stopped, so do not perform audio_be_write. */
> > return_tx_buffer(stream, buffer);
> > continue;
> > @@ -1261,7 +1279,7 @@ static void virtio_snd_pcm_in_cb(void *data, int available)
> > if (!virtio_queue_ready(buffer->vq)) {
> > return;
> > }
> > - if (!stream->active) {
> > + if (!(stream->state & VSND_PCMSTREAM_STATE_F_ACTIVE)) {
> > /* Stream has stopped, so do not perform audio_be_read. */
> > return_rx_buffer(stream, buffer);
> > continue;
> > @@ -1334,17 +1352,16 @@ static void virtio_snd_unrealize(DeviceState *dev)
> > qemu_del_vm_change_state_handler(vsnd->vmstate);
> > trace_virtio_snd_unrealize(vsnd);
> >
> > - if (vsnd->pcm.streams) {
> > + if (vsnd->streams) {
> > + virtio_snd_process_cmdq(vsnd);
> > for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
> > - stream = vsnd->pcm.streams[i];
> > - if (stream) {
> > - virtio_snd_process_cmdq(stream->s);
> > - virtio_snd_pcm_close(stream);
> > + stream = &vsnd->streams[i];
> > + if (stream->state & VSND_PCMSTREAM_STATE_F_PREPARED) {
> > + virtio_snd_pcm_flush(stream);
> > }
> > + virtio_snd_pcm_close(stream);
> > }
> > - g_free(vsnd->pcm.streams);
> > }
> > - g_free(vsnd->pcm.pcm_params);
> > g_free(vsnd->streams);
> > vsnd->streams = NULL;
> > virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]);
> > @@ -1378,6 +1395,9 @@ static void virtio_snd_reset(VirtIODevice *vdev)
> > VirtIOSoundPCMStream *stream = &vsnd->streams[i];
> > VirtIOSoundPCMBuffer *buffer;
> >
> > + virtio_snd_pcm_close(stream);
> > + stream->state = VSND_PCMSTREAM_STATE_UNINITIALIZED;
> > +
> > while ((buffer = QSIMPLEQ_FIRST(&stream->queue))) {
> > QSIMPLEQ_REMOVE_HEAD(&stream->queue, entry);
> > virtio_snd_pcm_buffer_free(buffer);
> > diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
> > index 41c63b3f23b..72ef34e0976 100644
> > --- a/include/hw/audio/virtio-snd.h
> > +++ b/include/hw/audio/virtio-snd.h
> > @@ -75,8 +75,6 @@ typedef struct VirtIOSoundPCMStream VirtIOSoundPCMStream;
> >
> > typedef struct virtio_snd_ctrl_command virtio_snd_ctrl_command;
> >
> > -typedef struct VirtIOSoundPCM VirtIOSoundPCM;
> > -
> > typedef struct VirtIOSoundPCMBuffer VirtIOSoundPCMBuffer;
> >
> > /*
> > @@ -121,31 +119,18 @@ struct VirtIOSoundPCMBuffer {
> > uint8_t data[];
> > };
> >
> > -struct VirtIOSoundPCM {
> > - /*
> > - * PCM parameters are a separate field instead of a VirtIOSoundPCMStream
> > - * field, because the operation of PCM control requests is first
> > - * VIRTIO_SND_R_PCM_SET_PARAMS and then VIRTIO_SND_R_PCM_PREPARE; this
> > - * means that some times we get parameters without having an allocated
> > - * stream yet.
> > - */
> > - virtio_snd_pcm_set_params *pcm_params;
> > - VirtIOSoundPCMStream **streams;
> > -};
> > -
> > struct VirtIOSoundPCMStream {
> > virtio_snd_pcm_info info;
> > virtio_snd_pcm_set_params params;
> > + uint32_t state;
> > /* channel position values (VIRTIO_SND_CHMAP_XXX) */
> > uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
> > VirtIOSound *s;
> > - bool flushing;
>
> Spurious change: this should be a separate patch.
>
> > audsettings as;
> > union {
> > SWVoiceIn *in;
> > SWVoiceOut *out;
> > } voice;
> > - bool active;
> > uint32_t latency_bytes;
> > QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) queue;
> > };
> > @@ -212,7 +197,6 @@ struct VirtIOSound {
> >
> > VirtQueue *queues[VIRTIO_SND_VQ_MAX];
> > uint64_t features;
> > - VirtIOSoundPCM pcm;
> > VirtIOSoundPCMStream *streams;
> > AudioBackend *audio_be;
> > VMChangeStateEntry *vmstate;
> > --
> > 2.47.3
> >
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH v3 5/9] hw/audio/virtio-sound: add stream state variable
2026-06-29 8:21 ` Michael S. Tsirkin
@ 2026-06-29 8:31 ` Manos Pitsidianakis
0 siblings, 0 replies; 26+ messages in thread
From: Manos Pitsidianakis @ 2026-06-29 8:31 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: Alexander Mikhalitsyn, qemu-devel, Volker Rümelin,
Marc-André Lureau, Stéphane Graber,
Daniel P . Berrangé, Gerd Hoffmann, Alexander Mikhalitsyn
On Mon, 29 Jun 2026 11:21, "Michael S. Tsirkin" <mst@redhat.com> wrote:
>On Mon, Jun 29, 2026 at 10:58:32AM +0300, Manos Pitsidianakis wrote:
>> On Fri, 26 Jun 2026 15:35, Alexander Mikhalitsyn <alexander@mihalicyn.com> wrote:
>> > From: Volker Rümelin <vr_qemu@t-online.de>
>> >
>> > So far, only rudimentary checks have been made to ensure that
>> > the guest only performs state transitions permitted in
>> > virtio-v1.2-csd01 5.14.6.6.1 PCM Command Lifecycle. Add a state
>> > variable per audio stream and check all state transitions.
>>
>>
>> This was on purpose: 5.14.6.6.1 is not a Device Requirement / normative
>> statement. (In my opinion it should have been).
>
>It's easy to add them - even strong ones (MUST) if it's clear from the description that this
>was always the intent, and no reasonable implementation would
>do anything else.
Agreed, will send a patch to virtio-comment. I think strictly adhering
to the state machine does not break any MUST requirement for the device,
so it should be backwards compatible.
>
>If not we can add weak ones (SHOULD).
>
>
>> I do not oppose keeping the state though, I chose to do it in the Rust
>> implementation (vhost-device-sound) after I wrote this one as well. It makes
>> sense. But please update the commit message to say that this is not about
>> spec compliance, but simply doing a sanity check following the PCM Command
>> Lifecycle section.
>>
>>
>> >
>> > Because only permitted state transitions are possible, only one
>> > copy of the audio stream parameters is required and these do not
>> > need to be initialised with default values.
>> >
>> > The state variable will also make it easier to restore the audio
>> > stream after migration.
>> >
>> > Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
>> > [AM: there were too many conflicts, I did `git checkout --ours -- <.>`
>> > and then reimplemented the patch idea
>> > /AM]
>> > Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
>> > ---
>> > v3:
>> > - explicitly call virtio_snd_pcm_close() from unrealize
>> > - remove a call to virtio_snd_pcm_flush() from virtio_snd_pcm_close()
>> > [ ^ this was my rebase mistake ]
>> > ---
>> > hw/audio/virtio-snd.c | 196 +++++++++++++++++++---------------
>> > include/hw/audio/virtio-snd.h | 18 +---
>> > 2 files changed, 109 insertions(+), 105 deletions(-)
>> >
>> > diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
>> > index 300ba13ffeb..68d737478f5 100644
>> > --- a/hw/audio/virtio-snd.c
>> > +++ b/hw/audio/virtio-snd.c
>> > @@ -30,11 +30,30 @@
>> > #define VIRTIO_SOUND_CHMAP_DEFAULT 0
>> > #define VIRTIO_SOUND_HDA_FN_NID 0
>> >
>> > +#define VSND_PCMSTREAM_STATE_F_PARAMS_SET 0x10000
>> > +#define VSND_PCMSTREAM_STATE_F_PREPARED 0x20000
>> > +#define VSND_PCMSTREAM_STATE_F_ACTIVE 0x40000
>> > +
>> > +#define VSND_PCMSTREAM_STATE_UNINITIALIZED 0
>> > +#define VSND_PCMSTREAM_STATE_PARAMS_SET (1 \
>> > + | VSND_PCMSTREAM_STATE_F_PARAMS_SET)
>> > +#define VSND_PCMSTREAM_STATE_PREPARED (2 \
>> > + | VSND_PCMSTREAM_STATE_F_PARAMS_SET \
>> > + | VSND_PCMSTREAM_STATE_F_PREPARED)
>> > +#define VSND_PCMSTREAM_STATE_STARTED (4 \
>> > + | VSND_PCMSTREAM_STATE_F_PARAMS_SET \
>> > + | VSND_PCMSTREAM_STATE_F_PREPARED \
>> > + | VSND_PCMSTREAM_STATE_F_ACTIVE)
>> > +#define VSND_PCMSTREAM_STATE_STOPPED (6 \
>> > + | VSND_PCMSTREAM_STATE_F_PARAMS_SET \
>> > + | VSND_PCMSTREAM_STATE_F_PREPARED)
>> > +#define VSND_PCMSTREAM_STATE_RELEASED (7 \
>> > + | VSND_PCMSTREAM_STATE_F_PARAMS_SET)
>>
>> Are the VSND_PCMSTREAM_STATE_F_* really needed? Seems excessive.
>>
>> I'd do: (did not type check/compile)
>>
>> + enum virtio_snd_pcm_state {
>> + VIRTIO_SND_PCM_STATE_UNINIT = 0,
>> + VIRTIO_SND_PCM_STATE_PARAMS_SET,
>> + VIRTIO_SND_PCM_STATE_PREPARED,
>> + VIRTIO_SND_PCM_STATE_STARTED,
>> + VIRTIO_SND_PCM_STATE_STOPPED,
>> + VIRTIO_SND_PCM_STATE_RELEASED,
>> + }
>>
>> Maybe even write a "method" "macro" for preparedness:
>>
>> +
>> + static inline bool virtio_snd_pcm_state_prepared(virtio_snd_pcm_state s) {
>> + return s > VIRTIO_SND_PCM_STATE_PARAMS_SET && s <
>> VIRTIO_SND_PCM_STATE_RELEASED
>> + }
>>
>> And "active" flag bit is only in STARTED state, so just check for equality.
>>
>> This is not a hard request, but it seems simpler to me and would prefer it.
>>
>> > +
>> > static void virtio_snd_pcm_out_cb(void *data, int available);
>> > static void virtio_snd_process_cmdq(VirtIOSound *s);
>> > static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream);
>> > static void virtio_snd_pcm_in_cb(void *data, int available);
>> > -static void virtio_snd_unrealize(DeviceState *dev);
>> >
>> > static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8)
>> > | BIT(VIRTIO_SND_PCM_FMT_U8)
>> > @@ -129,7 +148,7 @@ static VirtIOSoundPCMStream *virtio_snd_pcm_get_stream(VirtIOSound *s,
>> > uint32_t stream_id)
>> > {
>> > return stream_id >= s->snd_conf.streams ? NULL :
>> > - s->pcm.streams[stream_id];
>> > + &s->streams[stream_id];
>> > }
>> >
>> > /*
>> > @@ -141,8 +160,8 @@ static VirtIOSoundPCMStream *virtio_snd_pcm_get_stream(VirtIOSound *s,
>> > static virtio_snd_pcm_set_params *virtio_snd_pcm_get_params(VirtIOSound *s,
>> > uint32_t stream_id)
>> > {
>> > - return stream_id >= s->snd_conf.streams ? NULL
>> > - : &s->pcm.pcm_params[stream_id];
>> > + return stream_id >= s->snd_conf.streams ? NULL :
>> > + &s->streams[stream_id].params;
>> > }
>> >
>> > /*
>> > @@ -245,11 +264,10 @@ static void virtio_snd_handle_pcm_info(VirtIOSound *s,
>> >
>> > /*
>> > * Set the given stream params.
>> > - * Called by both virtio_snd_handle_pcm_set_params and during device
>> > - * initialization.
>> > * Returns the response status code. (VIRTIO_SND_S_*).
>> > *
>> > * @s: VirtIOSound device
>> > + * @stream_id: stream id
>> > * @params: The PCM params as defined in the virtio specification
>> > */
>> > static
>> > @@ -257,14 +275,25 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
>> > uint32_t stream_id,
>> > virtio_snd_pcm_set_params *params)
>> > {
>> > + VirtIOSoundPCMStream *stream;
>> > virtio_snd_pcm_set_params *st_params;
>> >
>> > - if (stream_id >= s->snd_conf.streams || s->pcm.pcm_params == NULL) {
>> > + if (stream_id >= s->snd_conf.streams) {
>> > virtio_error(VIRTIO_DEVICE(s), "Streams have not been initialized.\n");
>> > return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
>> > }
>> >
>> > - st_params = virtio_snd_pcm_get_params(s, stream_id);
>> > + stream = virtio_snd_pcm_get_stream(s, stream_id);
>> > +
>> > + switch (stream->state) {
>> > + case VSND_PCMSTREAM_STATE_UNINITIALIZED:
>> > + case VSND_PCMSTREAM_STATE_PARAMS_SET:
>> > + case VSND_PCMSTREAM_STATE_PREPARED:
>> > + case VSND_PCMSTREAM_STATE_RELEASED:
>> > + break;
>> > + default:
>> > + return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
>> > + }
>> >
>> > if (params->channels < 1 || params->channels > AUDIO_MAX_CHANNELS) {
>> > error_report("Number of channels is not supported.");
>> > @@ -281,6 +310,8 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
>> > return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
>> > }
>> >
>> > + st_params = virtio_snd_pcm_get_params(s, stream_id);
>> > +
>> > st_params->buffer_bytes = le32_to_cpu(params->buffer_bytes);
>> > st_params->period_bytes = le32_to_cpu(params->period_bytes);
>> > st_params->features = le32_to_cpu(params->features);
>> > @@ -289,6 +320,13 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
>> > st_params->format = params->format;
>> > st_params->rate = params->rate;
>> >
>> > + if (stream->state & VSND_PCMSTREAM_STATE_F_PREPARED) {
>> > + /* implicit VIRTIO_SND_R_PCM_RELEASE */
>> > + virtio_snd_pcm_flush(stream);
>> > + }
>> > +
>> > + stream->state = VSND_PCMSTREAM_STATE_PARAMS_SET;
>> > +
>> > return cpu_to_le32(VIRTIO_SND_S_OK);
>> > }
>> >
>> > @@ -398,15 +436,12 @@ static void virtio_snd_get_qemu_audsettings(audsettings *as,
>> > */
>> > static void virtio_snd_pcm_close(VirtIOSoundPCMStream *stream)
>> > {
>> > - if (stream) {
>> > - virtio_snd_pcm_flush(stream);
>> > - if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
>> > - audio_be_close_out(stream->s->audio_be, stream->voice.out);
>> > - stream->voice.out = NULL;
>> > - } else if (stream->info.direction == VIRTIO_SND_D_INPUT) {
>> > - audio_be_close_in(stream->s->audio_be, stream->voice.in);
>> > - stream->voice.in = NULL;
>> > - }
>> > + if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
>> > + audio_be_close_out(stream->s->audio_be, stream->voice.out);
>> > + stream->voice.out = NULL;
>> > + } else if (stream->info.direction == VIRTIO_SND_D_INPUT) {
>> > + audio_be_close_in(stream->s->audio_be, stream->voice.in);
>> > + stream->voice.in = NULL;
>> > }
>> > }
>> >
>> > @@ -423,32 +458,23 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
>> > virtio_snd_pcm_set_params *params;
>> > VirtIOSoundPCMStream *stream;
>> >
>> > - if (s->pcm.streams == NULL ||
>> > - s->pcm.pcm_params == NULL ||
>> > - stream_id >= s->snd_conf.streams) {
>> > + stream = virtio_snd_pcm_get_stream(s, stream_id);
>> > + if (!stream) {
>> > return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
>> > }
>> >
>> > - params = virtio_snd_pcm_get_params(s, stream_id);
>> > - if (params == NULL) {
>> > + switch (stream->state) {
>> > + case VSND_PCMSTREAM_STATE_PARAMS_SET:
>> > + case VSND_PCMSTREAM_STATE_PREPARED:
>> > + case VSND_PCMSTREAM_STATE_RELEASED:
>> > + break;
>> > + default:
>> > return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
>> > }
>> >
>> > - stream = virtio_snd_pcm_get_stream(s, stream_id);
>> > - if (stream == NULL) {
>> > - stream = &s->streams[stream_id];
>> > - stream->active = false;
>> > - stream->latency_bytes = 0;
>> > -
>> > - /*
>> > - * stream_id >= s->snd_conf.streams was checked before so this is
>> > - * in-bounds
>> > - */
>> > - s->pcm.streams[stream_id] = stream;
>> > - }
>> > + params = virtio_snd_pcm_get_params(s, stream_id);
>> >
>> > virtio_snd_get_qemu_audsettings(&as, params);
>> > - stream->params = *params;
>> >
>> > stream->positions[0] = VIRTIO_SND_CHMAP_FL;
>> > stream->positions[1] = VIRTIO_SND_CHMAP_FR;
>> > @@ -472,6 +498,8 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
>> > audio_be_set_volume_in_lr(s->audio_be, stream->voice.in, 0, 255, 255);
>> > }
>> >
>> > + stream->state = VSND_PCMSTREAM_STATE_PREPARED;
>> > +
>> > return cpu_to_le32(VIRTIO_SND_S_OK);
>> > }
>> >
>> > @@ -542,12 +570,28 @@ static uint32_t virtio_snd_pcm_start_stop(VirtIOSound *s,
>> > }
>> >
>> > if (start) {
>> > + switch (stream->state) {
>> > + case VSND_PCMSTREAM_STATE_PREPARED:
>> > + case VSND_PCMSTREAM_STATE_STOPPED:
>> > + break;
>> > + default:
>> > + return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
>> > + }
>> > +
>> > trace_virtio_snd_handle_pcm_start(stream_id);
>> > + stream->state = VSND_PCMSTREAM_STATE_STARTED;
>> > } else {
>> > + switch (stream->state) {
>> > + case VSND_PCMSTREAM_STATE_STARTED:
>> > + break;
>> > + default:
>> > + return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
>> > + }
>> > +
>> > trace_virtio_snd_handle_pcm_stop(stream_id);
>> > + stream->state = VSND_PCMSTREAM_STATE_STOPPED;
>> > }
>> >
>> > - stream->active = start;
>> > if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
>> > audio_be_set_active_out(s->audio_be, stream->voice.out, start);
>> > } else {
>> > @@ -641,6 +685,15 @@ static void virtio_snd_handle_pcm_release(VirtIOSound *s,
>> > return;
>> > }
>> >
>> > + switch (stream->state) {
>> > + case VSND_PCMSTREAM_STATE_PREPARED:
>> > + case VSND_PCMSTREAM_STATE_STOPPED:
>> > + break;
>> > + default:
>> > + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
>> > + return;
>> > + }
>> > +
>> > if (virtio_snd_pcm_get_io_msgs_count(stream)) {
>> > /*
>> > * virtio-v1.2-csd01, 5.14.6.6.5.1,
>> > @@ -655,6 +708,8 @@ static void virtio_snd_handle_pcm_release(VirtIOSound *s,
>> > virtio_snd_pcm_flush(stream);
>> > }
>> >
>> > + stream->state = VSND_PCMSTREAM_STATE_RELEASED;
>> > +
>> > cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
>> > }
>> >
>> > @@ -876,12 +931,11 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
>> > }
>> > stream_id = le32_to_cpu(hdr.stream_id);
>> >
>> > - if (stream_id >= vsnd->snd_conf.streams
>> > - || vsnd->pcm.streams[stream_id] == NULL) {
>> > + if (stream_id >= vsnd->snd_conf.streams) {
>> > goto tx_err;
>> > }
>> >
>> > - stream = vsnd->pcm.streams[stream_id];
>> > + stream = &vsnd->streams[stream_id];
>> > if (stream->info.direction != VIRTIO_SND_D_OUTPUT) {
>> > goto tx_err;
>> > }
>> > @@ -956,13 +1010,12 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
>> > }
>> > stream_id = le32_to_cpu(hdr.stream_id);
>> >
>> > - if (stream_id >= vsnd->snd_conf.streams
>> > - || !vsnd->pcm.streams[stream_id]) {
>> > + if (stream_id >= vsnd->snd_conf.streams) {
>> > goto rx_err;
>> > }
>> >
>> > - stream = vsnd->pcm.streams[stream_id];
>> > - if (stream == NULL || stream->info.direction != VIRTIO_SND_D_INPUT) {
>> > + stream = &vsnd->streams[stream_id];
>> > + if (stream->info.direction != VIRTIO_SND_D_INPUT) {
>> > goto rx_err;
>> > }
>> >
>> > @@ -1021,8 +1074,6 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
>> > ERRP_GUARD();
>> > VirtIOSound *vsnd = VIRTIO_SND(dev);
>> > VirtIODevice *vdev = VIRTIO_DEVICE(dev);
>> > - virtio_snd_pcm_set_params default_params = { 0 };
>> > - uint32_t status;
>> >
>> > trace_virtio_snd_realize(vsnd);
>> >
>> > @@ -1059,6 +1110,7 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
>> > for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
>> > VirtIOSoundPCMStream *stream = &vsnd->streams[i];
>> >
>> > + stream->state = VSND_PCMSTREAM_STATE_UNINITIALIZED;
>> > stream->s = vsnd;
>> > QSIMPLEQ_INIT(&stream->queue);
>> > stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID;
>> > @@ -1072,21 +1124,9 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
>> > stream->info.channels_max = 2;
>> > }
>> >
>> > - vsnd->pcm.streams =
>> > - g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams);
>> > - vsnd->pcm.pcm_params =
>> > - g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams);
>> > -
>> > virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config));
>> > virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1);
>> >
>> > - /* set default params for all streams */
>> > - default_params.features = 0;
>> > - default_params.buffer_bytes = cpu_to_le32(8192);
>> > - default_params.period_bytes = cpu_to_le32(2048);
>> > - default_params.channels = 2;
>> > - default_params.format = VIRTIO_SND_PCM_FMT_S16;
>> > - default_params.rate = VIRTIO_SND_PCM_RATE_48000;
>> > vsnd->queues[VIRTIO_SND_VQ_CONTROL] =
>> > virtio_add_queue(vdev, 64, virtio_snd_handle_ctrl);
>> > vsnd->queues[VIRTIO_SND_VQ_EVENT] =
>> > @@ -1097,28 +1137,6 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
>> > virtio_add_queue(vdev, 64, virtio_snd_handle_rx_xfer);
>> > QTAILQ_INIT(&vsnd->cmdq);
>> > QSIMPLEQ_INIT(&vsnd->invalid);
>> > -
>> > - for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
>> > - status = virtio_snd_set_pcm_params(vsnd, i, &default_params);
>> > - if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
>> > - error_setg(errp,
>> > - "Can't initialize stream params, device responded with %s.",
>> > - print_code(status));
>> > - goto error_cleanup;
>> > - }
>> > - status = virtio_snd_pcm_prepare(vsnd, i);
>> > - if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
>> > - error_setg(errp,
>> > - "Can't prepare streams, device responded with %s.",
>> > - print_code(status));
>> > - goto error_cleanup;
>> > - }
>> > - }
>> > -
>> > - return;
>> > -
>> > -error_cleanup:
>> > - virtio_snd_unrealize(dev);
>> > }
>> >
>> > static inline void update_latency(VirtIOSoundPCMStream *s, size_t used)
>> > @@ -1167,7 +1185,7 @@ static void virtio_snd_pcm_out_cb(void *data, int available)
>> > if (!virtio_queue_ready(buffer->vq)) {
>> > return;
>> > }
>> > - if (!stream->active) {
>> > + if (!(stream->state & VSND_PCMSTREAM_STATE_F_ACTIVE)) {
>> > /* Stream has stopped, so do not perform audio_be_write. */
>> > return_tx_buffer(stream, buffer);
>> > continue;
>> > @@ -1261,7 +1279,7 @@ static void virtio_snd_pcm_in_cb(void *data, int available)
>> > if (!virtio_queue_ready(buffer->vq)) {
>> > return;
>> > }
>> > - if (!stream->active) {
>> > + if (!(stream->state & VSND_PCMSTREAM_STATE_F_ACTIVE)) {
>> > /* Stream has stopped, so do not perform audio_be_read. */
>> > return_rx_buffer(stream, buffer);
>> > continue;
>> > @@ -1334,17 +1352,16 @@ static void virtio_snd_unrealize(DeviceState *dev)
>> > qemu_del_vm_change_state_handler(vsnd->vmstate);
>> > trace_virtio_snd_unrealize(vsnd);
>> >
>> > - if (vsnd->pcm.streams) {
>> > + if (vsnd->streams) {
>> > + virtio_snd_process_cmdq(vsnd);
>> > for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
>> > - stream = vsnd->pcm.streams[i];
>> > - if (stream) {
>> > - virtio_snd_process_cmdq(stream->s);
>> > - virtio_snd_pcm_close(stream);
>> > + stream = &vsnd->streams[i];
>> > + if (stream->state & VSND_PCMSTREAM_STATE_F_PREPARED) {
>> > + virtio_snd_pcm_flush(stream);
>> > }
>> > + virtio_snd_pcm_close(stream);
>> > }
>> > - g_free(vsnd->pcm.streams);
>> > }
>> > - g_free(vsnd->pcm.pcm_params);
>> > g_free(vsnd->streams);
>> > vsnd->streams = NULL;
>> > virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]);
>> > @@ -1378,6 +1395,9 @@ static void virtio_snd_reset(VirtIODevice *vdev)
>> > VirtIOSoundPCMStream *stream = &vsnd->streams[i];
>> > VirtIOSoundPCMBuffer *buffer;
>> >
>> > + virtio_snd_pcm_close(stream);
>> > + stream->state = VSND_PCMSTREAM_STATE_UNINITIALIZED;
>> > +
>> > while ((buffer = QSIMPLEQ_FIRST(&stream->queue))) {
>> > QSIMPLEQ_REMOVE_HEAD(&stream->queue, entry);
>> > virtio_snd_pcm_buffer_free(buffer);
>> > diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
>> > index 41c63b3f23b..72ef34e0976 100644
>> > --- a/include/hw/audio/virtio-snd.h
>> > +++ b/include/hw/audio/virtio-snd.h
>> > @@ -75,8 +75,6 @@ typedef struct VirtIOSoundPCMStream VirtIOSoundPCMStream;
>> >
>> > typedef struct virtio_snd_ctrl_command virtio_snd_ctrl_command;
>> >
>> > -typedef struct VirtIOSoundPCM VirtIOSoundPCM;
>> > -
>> > typedef struct VirtIOSoundPCMBuffer VirtIOSoundPCMBuffer;
>> >
>> > /*
>> > @@ -121,31 +119,18 @@ struct VirtIOSoundPCMBuffer {
>> > uint8_t data[];
>> > };
>> >
>> > -struct VirtIOSoundPCM {
>> > - /*
>> > - * PCM parameters are a separate field instead of a VirtIOSoundPCMStream
>> > - * field, because the operation of PCM control requests is first
>> > - * VIRTIO_SND_R_PCM_SET_PARAMS and then VIRTIO_SND_R_PCM_PREPARE; this
>> > - * means that some times we get parameters without having an allocated
>> > - * stream yet.
>> > - */
>> > - virtio_snd_pcm_set_params *pcm_params;
>> > - VirtIOSoundPCMStream **streams;
>> > -};
>> > -
>> > struct VirtIOSoundPCMStream {
>> > virtio_snd_pcm_info info;
>> > virtio_snd_pcm_set_params params;
>> > + uint32_t state;
>> > /* channel position values (VIRTIO_SND_CHMAP_XXX) */
>> > uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
>> > VirtIOSound *s;
>> > - bool flushing;
>>
>> Spurious change: this should be a separate patch.
>>
>> > audsettings as;
>> > union {
>> > SWVoiceIn *in;
>> > SWVoiceOut *out;
>> > } voice;
>> > - bool active;
>> > uint32_t latency_bytes;
>> > QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) queue;
>> > };
>> > @@ -212,7 +197,6 @@ struct VirtIOSound {
>> >
>> > VirtQueue *queues[VIRTIO_SND_VQ_MAX];
>> > uint64_t features;
>> > - VirtIOSoundPCM pcm;
>> > VirtIOSoundPCMStream *streams;
>> > AudioBackend *audio_be;
>> > VMChangeStateEntry *vmstate;
>> > --
>> > 2.47.3
>> >
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 6/9] hw/audio/virtio-sound: introduce virtio_snd_pcm_open()
2026-06-26 12:35 [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support Alexander Mikhalitsyn
` (4 preceding siblings ...)
2026-06-26 12:35 ` [PATCH v3 5/9] hw/audio/virtio-sound: add stream state variable Alexander Mikhalitsyn
@ 2026-06-26 12:35 ` Alexander Mikhalitsyn
2026-06-29 8:19 ` Manos Pitsidianakis
2026-06-26 12:35 ` [PATCH v3 7/9] hw/audio/virtio-sound: introduce virtio_snd_set_active() Alexander Mikhalitsyn
` (3 subsequent siblings)
9 siblings, 1 reply; 26+ messages in thread
From: Alexander Mikhalitsyn @ 2026-06-26 12:35 UTC (permalink / raw)
To: qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
From: Volker Rümelin <vr_qemu@t-online.de>
Split out the function virtio_snd_pcm_open() from
virtio_snd_pcm_prepare(). A later patch also needs
the new function. There is no functional change.
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
[AM: trivial rebase changes]
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/audio/virtio-snd.c | 60 ++++++++++++++++++++++++-------------------
1 file changed, 33 insertions(+), 27 deletions(-)
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 68d737478f5..d5242a5c761 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -429,6 +429,38 @@ static void virtio_snd_get_qemu_audsettings(audsettings *as,
as->big_endian = false; /* Conforming to VIRTIO 1.0: always little endian. */
}
+/*
+ * Open a stream.
+ *
+ * @stream: VirtIOSoundPCMStream *stream
+ */
+static void virtio_snd_pcm_open(VirtIOSoundPCMStream *stream)
+{
+ virtio_snd_get_qemu_audsettings(&stream->as, &stream->params);
+ stream->positions[0] = VIRTIO_SND_CHMAP_FL;
+ stream->positions[1] = VIRTIO_SND_CHMAP_FR;
+
+ if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
+ stream->voice.out = audio_be_open_out(stream->s->audio_be,
+ stream->voice.out,
+ "virtio-sound.out",
+ stream,
+ virtio_snd_pcm_out_cb,
+ &stream->as);
+ audio_be_set_volume_out_lr(stream->s->audio_be,
+ stream->voice.out, 0, 255, 255);
+ } else {
+ stream->voice.in = audio_be_open_in(stream->s->audio_be,
+ stream->voice.in,
+ "virtio-sound.in",
+ stream,
+ virtio_snd_pcm_in_cb,
+ &stream->as);
+ audio_be_set_volume_in_lr(stream->s->audio_be,
+ stream->voice.in, 0, 255, 255);
+ }
+}
+
/*
* Close a stream and free all its resources.
*
@@ -454,8 +486,6 @@ static void virtio_snd_pcm_close(VirtIOSoundPCMStream *stream)
*/
static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
{
- audsettings as;
- virtio_snd_pcm_set_params *params;
VirtIOSoundPCMStream *stream;
stream = virtio_snd_pcm_get_stream(s, stream_id);
@@ -472,31 +502,7 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
}
- params = virtio_snd_pcm_get_params(s, stream_id);
-
- virtio_snd_get_qemu_audsettings(&as, params);
-
- stream->positions[0] = VIRTIO_SND_CHMAP_FL;
- stream->positions[1] = VIRTIO_SND_CHMAP_FR;
- stream->as = as;
-
- if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
- stream->voice.out = audio_be_open_out(s->audio_be,
- stream->voice.out,
- "virtio-sound.out",
- stream,
- virtio_snd_pcm_out_cb,
- &as);
- audio_be_set_volume_out_lr(s->audio_be, stream->voice.out, 0, 255, 255);
- } else {
- stream->voice.in = audio_be_open_in(s->audio_be,
- stream->voice.in,
- "virtio-sound.in",
- stream,
- virtio_snd_pcm_in_cb,
- &as);
- audio_be_set_volume_in_lr(s->audio_be, stream->voice.in, 0, 255, 255);
- }
+ virtio_snd_pcm_open(stream);
stream->state = VSND_PCMSTREAM_STATE_PREPARED;
--
2.47.3
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v3 6/9] hw/audio/virtio-sound: introduce virtio_snd_pcm_open()
2026-06-26 12:35 ` [PATCH v3 6/9] hw/audio/virtio-sound: introduce virtio_snd_pcm_open() Alexander Mikhalitsyn
@ 2026-06-29 8:19 ` Manos Pitsidianakis
0 siblings, 0 replies; 26+ messages in thread
From: Manos Pitsidianakis @ 2026-06-29 8:19 UTC (permalink / raw)
To: Alexander Mikhalitsyn, qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
On Fri, 26 Jun 2026 15:35, Alexander Mikhalitsyn <alexander@mihalicyn.com> wrote:
>From: Volker Rümelin <vr_qemu@t-online.de>
>
>Split out the function virtio_snd_pcm_open() from
>virtio_snd_pcm_prepare(). A later patch also needs
>the new function. There is no functional change.
>
>Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
>[AM: trivial rebase changes]
>Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
>Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>---
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
> hw/audio/virtio-snd.c | 60 ++++++++++++++++++++++++-------------------
> 1 file changed, 33 insertions(+), 27 deletions(-)
>
>diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
>index 68d737478f5..d5242a5c761 100644
>--- a/hw/audio/virtio-snd.c
>+++ b/hw/audio/virtio-snd.c
>@@ -429,6 +429,38 @@ static void virtio_snd_get_qemu_audsettings(audsettings *as,
> as->big_endian = false; /* Conforming to VIRTIO 1.0: always little endian. */
> }
>
>+/*
>+ * Open a stream.
>+ *
>+ * @stream: VirtIOSoundPCMStream *stream
>+ */
>+static void virtio_snd_pcm_open(VirtIOSoundPCMStream *stream)
>+{
>+ virtio_snd_get_qemu_audsettings(&stream->as, &stream->params);
>+ stream->positions[0] = VIRTIO_SND_CHMAP_FL;
>+ stream->positions[1] = VIRTIO_SND_CHMAP_FR;
>+
>+ if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
>+ stream->voice.out = audio_be_open_out(stream->s->audio_be,
>+ stream->voice.out,
>+ "virtio-sound.out",
>+ stream,
>+ virtio_snd_pcm_out_cb,
>+ &stream->as);
>+ audio_be_set_volume_out_lr(stream->s->audio_be,
>+ stream->voice.out, 0, 255, 255);
>+ } else {
>+ stream->voice.in = audio_be_open_in(stream->s->audio_be,
>+ stream->voice.in,
>+ "virtio-sound.in",
>+ stream,
>+ virtio_snd_pcm_in_cb,
>+ &stream->as);
>+ audio_be_set_volume_in_lr(stream->s->audio_be,
>+ stream->voice.in, 0, 255, 255);
>+ }
>+}
>+
> /*
> * Close a stream and free all its resources.
> *
>@@ -454,8 +486,6 @@ static void virtio_snd_pcm_close(VirtIOSoundPCMStream *stream)
> */
> static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
> {
>- audsettings as;
>- virtio_snd_pcm_set_params *params;
> VirtIOSoundPCMStream *stream;
>
> stream = virtio_snd_pcm_get_stream(s, stream_id);
>@@ -472,31 +502,7 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
> return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> }
>
>- params = virtio_snd_pcm_get_params(s, stream_id);
>-
>- virtio_snd_get_qemu_audsettings(&as, params);
>-
>- stream->positions[0] = VIRTIO_SND_CHMAP_FL;
>- stream->positions[1] = VIRTIO_SND_CHMAP_FR;
>- stream->as = as;
>-
>- if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
>- stream->voice.out = audio_be_open_out(s->audio_be,
>- stream->voice.out,
>- "virtio-sound.out",
>- stream,
>- virtio_snd_pcm_out_cb,
>- &as);
>- audio_be_set_volume_out_lr(s->audio_be, stream->voice.out, 0, 255, 255);
>- } else {
>- stream->voice.in = audio_be_open_in(s->audio_be,
>- stream->voice.in,
>- "virtio-sound.in",
>- stream,
>- virtio_snd_pcm_in_cb,
>- &as);
>- audio_be_set_volume_in_lr(s->audio_be, stream->voice.in, 0, 255, 255);
>- }
>+ virtio_snd_pcm_open(stream);
>
> stream->state = VSND_PCMSTREAM_STATE_PREPARED;
>
>--
>2.47.3
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 7/9] hw/audio/virtio-sound: introduce virtio_snd_set_active()
2026-06-26 12:35 [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support Alexander Mikhalitsyn
` (5 preceding siblings ...)
2026-06-26 12:35 ` [PATCH v3 6/9] hw/audio/virtio-sound: introduce virtio_snd_pcm_open() Alexander Mikhalitsyn
@ 2026-06-26 12:35 ` Alexander Mikhalitsyn
2026-06-26 12:35 ` [PATCH v3 8/9] hw/audio/virtio-sound: remove channel positions field from VirtIOSoundPCMStream Alexander Mikhalitsyn
` (2 subsequent siblings)
9 siblings, 0 replies; 26+ messages in thread
From: Alexander Mikhalitsyn @ 2026-06-26 12:35 UTC (permalink / raw)
To: qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
From: Volker Rümelin <vr_qemu@t-online.de>
Split out the function virtio_snd_pcm_set_active() from
virtio_snd_pcm_start_stop(). A later patch also needs this
new funcion. There is no functional change.
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
[AM: trivial rebase changes]
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/audio/virtio-snd.c | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index d5242a5c761..c9c93bd090a 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -461,6 +461,21 @@ static void virtio_snd_pcm_open(VirtIOSoundPCMStream *stream)
}
}
+/*
+ * Activate/deactivate a stream.
+ *
+ * @stream: VirtIOSoundPCMStream *stream
+ * @active: whether to activate or deactivate the stream
+ */
+static void virtio_snd_pcm_set_active(VirtIOSoundPCMStream *stream, bool active)
+{
+ if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
+ audio_be_set_active_out(stream->s->audio_be, stream->voice.out, active);
+ } else {
+ audio_be_set_active_in(stream->s->audio_be, stream->voice.in, active);
+ }
+}
+
/*
* Close a stream and free all its resources.
*
@@ -598,11 +613,7 @@ static uint32_t virtio_snd_pcm_start_stop(VirtIOSound *s,
stream->state = VSND_PCMSTREAM_STATE_STOPPED;
}
- if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
- audio_be_set_active_out(s->audio_be, stream->voice.out, start);
- } else {
- audio_be_set_active_in(s->audio_be, stream->voice.in, start);
- }
+ virtio_snd_pcm_set_active(stream, start);
return cpu_to_le32(VIRTIO_SND_S_OK);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH v3 8/9] hw/audio/virtio-sound: remove channel positions field from VirtIOSoundPCMStream
2026-06-26 12:35 [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support Alexander Mikhalitsyn
` (6 preceding siblings ...)
2026-06-26 12:35 ` [PATCH v3 7/9] hw/audio/virtio-sound: introduce virtio_snd_set_active() Alexander Mikhalitsyn
@ 2026-06-26 12:35 ` Alexander Mikhalitsyn
2026-06-26 14:12 ` marcandre.lureau
2026-06-29 8:22 ` Manos Pitsidianakis
2026-06-26 12:35 ` [PATCH v3 9/9] hw/audio/virtio-sound: add missing vmstate fields Alexander Mikhalitsyn
2026-06-29 11:04 ` [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support Manos Pitsidianakis
9 siblings, 2 replies; 26+ messages in thread
From: Alexander Mikhalitsyn @ 2026-06-26 12:35 UTC (permalink / raw)
To: qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
From: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
This field seems to be useless currently, as we
don't implement VIRTIO_SND_R_CHMAP_INFO.
Suggested-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
---
v3:
- this patch was added
---
hw/audio/virtio-snd.c | 2 --
include/hw/audio/virtio-snd.h | 2 --
2 files changed, 4 deletions(-)
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index c9c93bd090a..81ba1e1a277 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -437,8 +437,6 @@ static void virtio_snd_get_qemu_audsettings(audsettings *as,
static void virtio_snd_pcm_open(VirtIOSoundPCMStream *stream)
{
virtio_snd_get_qemu_audsettings(&stream->as, &stream->params);
- stream->positions[0] = VIRTIO_SND_CHMAP_FL;
- stream->positions[1] = VIRTIO_SND_CHMAP_FR;
if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
stream->voice.out = audio_be_open_out(stream->s->audio_be,
diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
index 72ef34e0976..85d5d7c8619 100644
--- a/include/hw/audio/virtio-snd.h
+++ b/include/hw/audio/virtio-snd.h
@@ -123,8 +123,6 @@ struct VirtIOSoundPCMStream {
virtio_snd_pcm_info info;
virtio_snd_pcm_set_params params;
uint32_t state;
- /* channel position values (VIRTIO_SND_CHMAP_XXX) */
- uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
VirtIOSound *s;
audsettings as;
union {
--
2.47.3
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v3 8/9] hw/audio/virtio-sound: remove channel positions field from VirtIOSoundPCMStream
2026-06-26 12:35 ` [PATCH v3 8/9] hw/audio/virtio-sound: remove channel positions field from VirtIOSoundPCMStream Alexander Mikhalitsyn
@ 2026-06-26 14:12 ` marcandre.lureau
2026-06-29 8:22 ` Manos Pitsidianakis
1 sibling, 0 replies; 26+ messages in thread
From: marcandre.lureau @ 2026-06-26 14:12 UTC (permalink / raw)
To: Alexander Mikhalitsyn
Cc: qemu-devel, Volker Rümelin, Marc-André Lureau,
Manos Pitsidianakis, Stéphane Graber,
Daniel P . Berrangé, Gerd Hoffmann, Michael S. Tsirkin,
Alexander Mikhalitsyn
On Fri, 26 Jun 2026 14:35:30 +0200, Alexander Mikhalitsyn <alexander@mihalicyn.com> wrote:
> This field seems to be useless currently, as we
> don't implement VIRTIO_SND_R_CHMAP_INFO.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
--
Marc-André Lureau <marcandre.lureau@redhat.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 8/9] hw/audio/virtio-sound: remove channel positions field from VirtIOSoundPCMStream
2026-06-26 12:35 ` [PATCH v3 8/9] hw/audio/virtio-sound: remove channel positions field from VirtIOSoundPCMStream Alexander Mikhalitsyn
2026-06-26 14:12 ` marcandre.lureau
@ 2026-06-29 8:22 ` Manos Pitsidianakis
1 sibling, 0 replies; 26+ messages in thread
From: Manos Pitsidianakis @ 2026-06-29 8:22 UTC (permalink / raw)
To: Alexander Mikhalitsyn, qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
On Fri, 26 Jun 2026 15:35, Alexander Mikhalitsyn <alexander@mihalicyn.com> wrote:
>From: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
>
>This field seems to be useless currently, as we
>don't implement VIRTIO_SND_R_CHMAP_INFO.
>
>Suggested-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
>---
You could move this patch at the start of the series so that you don't
need to move around lines that touch positions and then remove them.
Either way:
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
>v3:
> - this patch was added
>---
> hw/audio/virtio-snd.c | 2 --
> include/hw/audio/virtio-snd.h | 2 --
> 2 files changed, 4 deletions(-)
>
>diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
>index c9c93bd090a..81ba1e1a277 100644
>--- a/hw/audio/virtio-snd.c
>+++ b/hw/audio/virtio-snd.c
>@@ -437,8 +437,6 @@ static void virtio_snd_get_qemu_audsettings(audsettings *as,
> static void virtio_snd_pcm_open(VirtIOSoundPCMStream *stream)
> {
> virtio_snd_get_qemu_audsettings(&stream->as, &stream->params);
>- stream->positions[0] = VIRTIO_SND_CHMAP_FL;
>- stream->positions[1] = VIRTIO_SND_CHMAP_FR;
>
> if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
> stream->voice.out = audio_be_open_out(stream->s->audio_be,
>diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
>index 72ef34e0976..85d5d7c8619 100644
>--- a/include/hw/audio/virtio-snd.h
>+++ b/include/hw/audio/virtio-snd.h
>@@ -123,8 +123,6 @@ struct VirtIOSoundPCMStream {
> virtio_snd_pcm_info info;
> virtio_snd_pcm_set_params params;
> uint32_t state;
>- /* channel position values (VIRTIO_SND_CHMAP_XXX) */
>- uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
> VirtIOSound *s;
> audsettings as;
> union {
>--
>2.47.3
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 9/9] hw/audio/virtio-sound: add missing vmstate fields
2026-06-26 12:35 [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support Alexander Mikhalitsyn
` (7 preceding siblings ...)
2026-06-26 12:35 ` [PATCH v3 8/9] hw/audio/virtio-sound: remove channel positions field from VirtIOSoundPCMStream Alexander Mikhalitsyn
@ 2026-06-26 12:35 ` Alexander Mikhalitsyn
2026-06-26 14:12 ` marcandre.lureau
2026-06-29 8:23 ` Manos Pitsidianakis
2026-06-29 11:04 ` [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support Manos Pitsidianakis
9 siblings, 2 replies; 26+ messages in thread
From: Alexander Mikhalitsyn @ 2026-06-26 12:35 UTC (permalink / raw)
To: qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
From: Volker Rümelin <vr_qemu@t-online.de>
The virtio-sound device is currently not migratable. Add the
missing VMSTATE fields, enable migration and reconnect the audio
streams after migration.
The queue_inuse[] array variables mimic the inuse variable in
struct VirtQueue which is private. They are needed to restart
the virtio queues after migration.
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
[AM: trivial rebase changes]
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
---
v3:
- added latency_bytes field to VMStateDescription
As suggested by Marc-André Lureau:
- removed the "rc" variable from virtio_snd_post_load()
- dropped info field from VMStateDescription, because
it can't be modified by guest and initialized only from realize
- added minimum_version_id/version_id so we can extend VMStateDescription
without breaking compatibility in the future
---
hw/audio/virtio-snd.c | 80 +++++++++++++++++++++++++++++++----
include/hw/audio/virtio-snd.h | 1 +
2 files changed, 73 insertions(+), 8 deletions(-)
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 81ba1e1a277..7af0b63c03b 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -24,7 +24,6 @@
#include "qapi/error.h"
#include "hw/audio/virtio-snd.h"
-#define VIRTIO_SOUND_VM_VERSION 1
#define VIRTIO_SOUND_JACK_DEFAULT 0
#define VIRTIO_SOUND_STREAM_DEFAULT 2
#define VIRTIO_SOUND_CHMAP_DEFAULT 0
@@ -78,17 +77,40 @@ static uint32_t supported_rates = BIT(VIRTIO_SND_PCM_RATE_5512)
| BIT(VIRTIO_SND_PCM_RATE_192000)
| BIT(VIRTIO_SND_PCM_RATE_384000);
+static const VMStateDescription vmstate_virtio_snd_stream = {
+ .name = "virtio-sound-stream",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(state, VirtIOSoundPCMStream),
+ VMSTATE_UINT32(params.buffer_bytes, VirtIOSoundPCMStream),
+ VMSTATE_UINT32(params.period_bytes, VirtIOSoundPCMStream),
+ VMSTATE_UINT32(params.features, VirtIOSoundPCMStream),
+ VMSTATE_UINT8(params.channels, VirtIOSoundPCMStream),
+ VMSTATE_UINT8(params.format, VirtIOSoundPCMStream),
+ VMSTATE_UINT8(params.rate, VirtIOSoundPCMStream),
+ VMSTATE_UINT32(latency_bytes, VirtIOSoundPCMStream),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static const VMStateDescription vmstate_virtio_snd_device = {
- .name = TYPE_VIRTIO_SND,
- .version_id = VIRTIO_SOUND_VM_VERSION,
- .minimum_version_id = VIRTIO_SOUND_VM_VERSION,
+ .name = "virtio-sound-device",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(queue_inuse, VirtIOSound, VIRTIO_SND_VQ_MAX),
+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(streams, VirtIOSound,
+ snd_conf.streams,
+ vmstate_virtio_snd_stream, VirtIOSoundPCMStream),
+ VMSTATE_END_OF_LIST()
+ },
};
static const VMStateDescription vmstate_virtio_snd = {
- .name = TYPE_VIRTIO_SND,
- .unmigratable = 1,
- .minimum_version_id = VIRTIO_SOUND_VM_VERSION,
- .version_id = VIRTIO_SOUND_VM_VERSION,
+ .name = "virtio-sound",
+ .version_id = 1,
+ .minimum_version_id = 1,
.fields = (const VMStateField[]) {
VMSTATE_VIRTIO_DEVICE,
VMSTATE_END_OF_LIST()
@@ -799,6 +821,7 @@ process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd)
sizeof(virtio_snd_hdr));
virtqueue_push(cmd->vq, cmd->elem,
sizeof(virtio_snd_hdr) + cmd->payload_size);
+ s->queue_inuse[VIRTIO_SND_VQ_CONTROL] -= 1;
virtio_notify(VIRTIO_DEVICE(s), cmd->vq);
}
@@ -845,6 +868,7 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
while (elem) {
+ s->queue_inuse[VIRTIO_SND_VQ_CONTROL] += 1;
cmd = g_new0(virtio_snd_ctrl_command, 1);
cmd->elem = elem;
cmd->vq = vq;
@@ -955,6 +979,7 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
goto tx_err;
}
+ vsnd->queue_inuse[VIRTIO_SND_VQ_TX] += 1;
size = iov_size(elem->out_sg, elem->out_num) - msg_sz;
buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
@@ -1034,6 +1059,7 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
goto rx_err;
}
+ vsnd->queue_inuse[VIRTIO_SND_VQ_RX] += 1;
size = iov_size(elem->in_sg, elem->in_num) -
sizeof(virtio_snd_pcm_status);
buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
@@ -1175,6 +1201,7 @@ static inline void return_tx_buffer(VirtIOSoundPCMStream *stream,
virtqueue_push(buffer->vq,
buffer->elem,
sizeof(virtio_snd_pcm_status));
+ stream->s->queue_inuse[VIRTIO_SND_VQ_TX] -= 1;
virtio_notify(VIRTIO_DEVICE(stream->s), buffer->vq);
QSIMPLEQ_REMOVE(&stream->queue,
buffer,
@@ -1268,6 +1295,7 @@ static inline void return_rx_buffer(VirtIOSoundPCMStream *stream,
virtqueue_push(buffer->vq,
buffer->elem,
sizeof(virtio_snd_pcm_status) + buffer->size);
+ stream->s->queue_inuse[VIRTIO_SND_VQ_RX] -= 1;
virtio_notify(VIRTIO_DEVICE(stream->s), buffer->vq);
QSIMPLEQ_REMOVE(&stream->queue,
buffer,
@@ -1386,6 +1414,37 @@ static void virtio_snd_unrealize(DeviceState *dev)
virtio_cleanup(vdev);
}
+static int virtio_snd_post_load(VirtIODevice *vdev)
+{
+ VirtIOSound *s = VIRTIO_SND(vdev);
+ uint32_t i;
+
+ for (i = 0; i < s->snd_conf.streams; i++) {
+ struct VirtIOSoundPCMStream *stream;
+
+ stream = virtio_snd_pcm_get_stream(s, i);
+ if (stream->state & VSND_PCMSTREAM_STATE_F_PREPARED) {
+ virtio_snd_pcm_open(stream);
+
+ if (stream->state & VSND_PCMSTREAM_STATE_F_ACTIVE) {
+ virtio_snd_pcm_set_active(stream, true);
+ }
+ }
+ }
+
+ for (i = 0; i < VIRTIO_SND_VQ_MAX; i++) {
+ if (s->queue_inuse[i]) {
+ if (!virtqueue_rewind(s->queues[i], s->queue_inuse[i])) {
+ error_report(
+ "virtio-snd: could not rewind %u elements in queue %u",
+ s->queue_inuse[i], i);
+ }
+ s->queue_inuse[i] = 0;
+ }
+ }
+
+ return 0;
+}
static void virtio_snd_reset(VirtIODevice *vdev)
{
@@ -1418,6 +1477,10 @@ static void virtio_snd_reset(VirtIODevice *vdev)
virtio_snd_pcm_buffer_free(buffer);
}
}
+
+ for (i = 0; i < VIRTIO_SND_VQ_MAX; i++) {
+ vsnd->queue_inuse[i] = 0;
+ }
}
static void virtio_snd_class_init(ObjectClass *klass, const void *data)
@@ -1431,6 +1494,7 @@ static void virtio_snd_class_init(ObjectClass *klass, const void *data)
dc->vmsd = &vmstate_virtio_snd;
vdc->vmsd = &vmstate_virtio_snd_device;
+ vdc->post_load = virtio_snd_post_load;
vdc->realize = virtio_snd_realize;
vdc->unrealize = virtio_snd_unrealize;
vdc->get_config = virtio_snd_get_config;
diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
index 85d5d7c8619..384d2868c19 100644
--- a/include/hw/audio/virtio-snd.h
+++ b/include/hw/audio/virtio-snd.h
@@ -194,6 +194,7 @@ struct VirtIOSound {
VirtIODevice parent_obj;
VirtQueue *queues[VIRTIO_SND_VQ_MAX];
+ uint32_t queue_inuse[VIRTIO_SND_VQ_MAX];
uint64_t features;
VirtIOSoundPCMStream *streams;
AudioBackend *audio_be;
--
2.47.3
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v3 9/9] hw/audio/virtio-sound: add missing vmstate fields
2026-06-26 12:35 ` [PATCH v3 9/9] hw/audio/virtio-sound: add missing vmstate fields Alexander Mikhalitsyn
@ 2026-06-26 14:12 ` marcandre.lureau
2026-06-29 8:23 ` Manos Pitsidianakis
1 sibling, 0 replies; 26+ messages in thread
From: marcandre.lureau @ 2026-06-26 14:12 UTC (permalink / raw)
To: Alexander Mikhalitsyn
Cc: qemu-devel, Volker Rümelin, Marc-André Lureau,
Manos Pitsidianakis, Stéphane Graber,
Daniel P . Berrangé, Gerd Hoffmann, Michael S. Tsirkin,
Alexander Mikhalitsyn
On Fri, 26 Jun 2026 14:35:31 +0200, Alexander Mikhalitsyn <alexander@mihalicyn.com> wrote:
> The virtio-sound device is currently not migratable. Add the
> missing VMSTATE fields, enable migration and reconnect the audio
> streams after migration.
>
> The queue_inuse[] array variables mimic the inuse variable in
> struct VirtQueue which is private. They are needed to restart
> the virtio queues after migration.
>
> [...]
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
--
Marc-André Lureau <marcandre.lureau@redhat.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 9/9] hw/audio/virtio-sound: add missing vmstate fields
2026-06-26 12:35 ` [PATCH v3 9/9] hw/audio/virtio-sound: add missing vmstate fields Alexander Mikhalitsyn
2026-06-26 14:12 ` marcandre.lureau
@ 2026-06-29 8:23 ` Manos Pitsidianakis
1 sibling, 0 replies; 26+ messages in thread
From: Manos Pitsidianakis @ 2026-06-29 8:23 UTC (permalink / raw)
To: Alexander Mikhalitsyn, qemu-devel
Cc: Volker Rümelin, Marc-André Lureau, Manos Pitsidianakis,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Alexander Mikhalitsyn, Michael S. Tsirkin, Alexander Mikhalitsyn
On Fri, 26 Jun 2026 15:35, Alexander Mikhalitsyn <alexander@mihalicyn.com> wrote:
>From: Volker Rümelin <vr_qemu@t-online.de>
>
>The virtio-sound device is currently not migratable. Add the
>missing VMSTATE fields, enable migration and reconnect the audio
>streams after migration.
>
>The queue_inuse[] array variables mimic the inuse variable in
>struct VirtQueue which is private. They are needed to restart
>the virtio queues after migration.
>
>Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
>[AM: trivial rebase changes]
>Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
>---
>v3:
> - added latency_bytes field to VMStateDescription
>
> As suggested by Marc-André Lureau:
> - removed the "rc" variable from virtio_snd_post_load()
> - dropped info field from VMStateDescription, because
> it can't be modified by guest and initialized only from realize
> - added minimum_version_id/version_id so we can extend VMStateDescription
> without breaking compatibility in the future
>---
> hw/audio/virtio-snd.c | 80 +++++++++++++++++++++++++++++++----
> include/hw/audio/virtio-snd.h | 1 +
> 2 files changed, 73 insertions(+), 8 deletions(-)
>
>diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
>index 81ba1e1a277..7af0b63c03b 100644
>--- a/hw/audio/virtio-snd.c
>+++ b/hw/audio/virtio-snd.c
>@@ -24,7 +24,6 @@
> #include "qapi/error.h"
> #include "hw/audio/virtio-snd.h"
>
>-#define VIRTIO_SOUND_VM_VERSION 1
> #define VIRTIO_SOUND_JACK_DEFAULT 0
> #define VIRTIO_SOUND_STREAM_DEFAULT 2
> #define VIRTIO_SOUND_CHMAP_DEFAULT 0
>@@ -78,17 +77,40 @@ static uint32_t supported_rates = BIT(VIRTIO_SND_PCM_RATE_5512)
> | BIT(VIRTIO_SND_PCM_RATE_192000)
> | BIT(VIRTIO_SND_PCM_RATE_384000);
>
>+static const VMStateDescription vmstate_virtio_snd_stream = {
>+ .name = "virtio-sound-stream",
>+ .version_id = 1,
>+ .minimum_version_id = 1,
>+ .fields = (const VMStateField[]) {
>+ VMSTATE_UINT32(state, VirtIOSoundPCMStream),
>+ VMSTATE_UINT32(params.buffer_bytes, VirtIOSoundPCMStream),
>+ VMSTATE_UINT32(params.period_bytes, VirtIOSoundPCMStream),
>+ VMSTATE_UINT32(params.features, VirtIOSoundPCMStream),
>+ VMSTATE_UINT8(params.channels, VirtIOSoundPCMStream),
>+ VMSTATE_UINT8(params.format, VirtIOSoundPCMStream),
>+ VMSTATE_UINT8(params.rate, VirtIOSoundPCMStream),
>+ VMSTATE_UINT32(latency_bytes, VirtIOSoundPCMStream),
>+ VMSTATE_END_OF_LIST()
>+ },
>+};
>+
> static const VMStateDescription vmstate_virtio_snd_device = {
>- .name = TYPE_VIRTIO_SND,
>- .version_id = VIRTIO_SOUND_VM_VERSION,
>- .minimum_version_id = VIRTIO_SOUND_VM_VERSION,
>+ .name = "virtio-sound-device",
>+ .version_id = 1,
>+ .minimum_version_id = 1,
>+ .fields = (const VMStateField[]) {
>+ VMSTATE_UINT32_ARRAY(queue_inuse, VirtIOSound, VIRTIO_SND_VQ_MAX),
>+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(streams, VirtIOSound,
>+ snd_conf.streams,
>+ vmstate_virtio_snd_stream, VirtIOSoundPCMStream),
>+ VMSTATE_END_OF_LIST()
>+ },
> };
>
> static const VMStateDescription vmstate_virtio_snd = {
>- .name = TYPE_VIRTIO_SND,
>- .unmigratable = 1,
>- .minimum_version_id = VIRTIO_SOUND_VM_VERSION,
>- .version_id = VIRTIO_SOUND_VM_VERSION,
>+ .name = "virtio-sound",
Why change the name? It differentiates between the device impl and
virtio-sound-pci wrapper device.
>+ .version_id = 1,
>+ .minimum_version_id = 1,
> .fields = (const VMStateField[]) {
> VMSTATE_VIRTIO_DEVICE,
> VMSTATE_END_OF_LIST()
>@@ -799,6 +821,7 @@ process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd)
> sizeof(virtio_snd_hdr));
> virtqueue_push(cmd->vq, cmd->elem,
> sizeof(virtio_snd_hdr) + cmd->payload_size);
>+ s->queue_inuse[VIRTIO_SND_VQ_CONTROL] -= 1;
Let's do a g_assert that this is > 0 before decrementing it.
> virtio_notify(VIRTIO_DEVICE(s), cmd->vq);
> }
>
>@@ -845,6 +868,7 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
>
> elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
> while (elem) {
>+ s->queue_inuse[VIRTIO_SND_VQ_CONTROL] += 1;
> cmd = g_new0(virtio_snd_ctrl_command, 1);
> cmd->elem = elem;
> cmd->vq = vq;
>@@ -955,6 +979,7 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
> goto tx_err;
> }
>
>+ vsnd->queue_inuse[VIRTIO_SND_VQ_TX] += 1;
> size = iov_size(elem->out_sg, elem->out_num) - msg_sz;
>
> buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
>@@ -1034,6 +1059,7 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
> goto rx_err;
> }
>
>+ vsnd->queue_inuse[VIRTIO_SND_VQ_RX] += 1;
> size = iov_size(elem->in_sg, elem->in_num) -
> sizeof(virtio_snd_pcm_status);
> buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
>@@ -1175,6 +1201,7 @@ static inline void return_tx_buffer(VirtIOSoundPCMStream *stream,
> virtqueue_push(buffer->vq,
> buffer->elem,
> sizeof(virtio_snd_pcm_status));
>+ stream->s->queue_inuse[VIRTIO_SND_VQ_TX] -= 1;
Ditto
> virtio_notify(VIRTIO_DEVICE(stream->s), buffer->vq);
> QSIMPLEQ_REMOVE(&stream->queue,
> buffer,
>@@ -1268,6 +1295,7 @@ static inline void return_rx_buffer(VirtIOSoundPCMStream *stream,
> virtqueue_push(buffer->vq,
> buffer->elem,
> sizeof(virtio_snd_pcm_status) + buffer->size);
>+ stream->s->queue_inuse[VIRTIO_SND_VQ_RX] -= 1;
Ditto
> virtio_notify(VIRTIO_DEVICE(stream->s), buffer->vq);
> QSIMPLEQ_REMOVE(&stream->queue,
> buffer,
>@@ -1386,6 +1414,37 @@ static void virtio_snd_unrealize(DeviceState *dev)
> virtio_cleanup(vdev);
> }
>
>+static int virtio_snd_post_load(VirtIODevice *vdev)
>+{
>+ VirtIOSound *s = VIRTIO_SND(vdev);
>+ uint32_t i;
>+
>+ for (i = 0; i < s->snd_conf.streams; i++) {
>+ struct VirtIOSoundPCMStream *stream;
>+
>+ stream = virtio_snd_pcm_get_stream(s, i);
>+ if (stream->state & VSND_PCMSTREAM_STATE_F_PREPARED) {
>+ virtio_snd_pcm_open(stream);
>+
>+ if (stream->state & VSND_PCMSTREAM_STATE_F_ACTIVE) {
>+ virtio_snd_pcm_set_active(stream, true);
>+ }
>+ }
>+ }
>+
>+ for (i = 0; i < VIRTIO_SND_VQ_MAX; i++) {
>+ if (s->queue_inuse[i]) {
>+ if (!virtqueue_rewind(s->queues[i], s->queue_inuse[i])) {
>+ error_report(
>+ "virtio-snd: could not rewind %u elements in queue %u",
>+ s->queue_inuse[i], i);
>+ }
>+ s->queue_inuse[i] = 0;
>+ }
>+ }
>+
>+ return 0;
>+}
>
> static void virtio_snd_reset(VirtIODevice *vdev)
> {
>@@ -1418,6 +1477,10 @@ static void virtio_snd_reset(VirtIODevice *vdev)
> virtio_snd_pcm_buffer_free(buffer);
> }
> }
>+
>+ for (i = 0; i < VIRTIO_SND_VQ_MAX; i++) {
>+ vsnd->queue_inuse[i] = 0;
>+ }
> }
>
> static void virtio_snd_class_init(ObjectClass *klass, const void *data)
>@@ -1431,6 +1494,7 @@ static void virtio_snd_class_init(ObjectClass *klass, const void *data)
>
> dc->vmsd = &vmstate_virtio_snd;
> vdc->vmsd = &vmstate_virtio_snd_device;
>+ vdc->post_load = virtio_snd_post_load;
> vdc->realize = virtio_snd_realize;
> vdc->unrealize = virtio_snd_unrealize;
> vdc->get_config = virtio_snd_get_config;
>diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
>index 85d5d7c8619..384d2868c19 100644
>--- a/include/hw/audio/virtio-snd.h
>+++ b/include/hw/audio/virtio-snd.h
>@@ -194,6 +194,7 @@ struct VirtIOSound {
> VirtIODevice parent_obj;
>
> VirtQueue *queues[VIRTIO_SND_VQ_MAX];
>+ uint32_t queue_inuse[VIRTIO_SND_VQ_MAX];
> uint64_t features;
> VirtIOSoundPCMStream *streams;
> AudioBackend *audio_be;
>--
>2.47.3
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support
2026-06-26 12:35 [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support Alexander Mikhalitsyn
` (8 preceding siblings ...)
2026-06-26 12:35 ` [PATCH v3 9/9] hw/audio/virtio-sound: add missing vmstate fields Alexander Mikhalitsyn
@ 2026-06-29 11:04 ` Manos Pitsidianakis
2026-06-29 11:32 ` Aleksandr Mikhalitsyn
9 siblings, 1 reply; 26+ messages in thread
From: Manos Pitsidianakis @ 2026-06-29 11:04 UTC (permalink / raw)
To: Alexander Mikhalitsyn
Cc: qemu-devel, Volker Rümelin, Marc-André Lureau,
Stéphane Graber, Daniel P . Berrangé, Gerd Hoffmann,
Michael S. Tsirkin, Alexander Mikhalitsyn
Hi Alexander,
On Fri, Jun 26, 2026 at 3:35 PM Alexander Mikhalitsyn
<alexander@mihalicyn.com> wrote:
>
> From: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
Could you please send your patches from your
aleksandr.mikhalitsyn@futurfusion.io address for the next revision?
Replying to review comments with your personal email is fine, but the
s-o-b should match your sending address. We do not know if the address
belongs to you otherwise. This is not explicitly stated in our Code
Provenance documentation but we need a way to verify your S-o-b
provenance.
Thanks,
>
> Dear friends,
>
> This patchset is aimed to support virtio-sound live migration and based on
> pre-existing Volker Rümelin's patches from qemu-devel lists [1]. I tried
> to ask (https://lore.kernel.org/qemu-devel/9d7ea128c711c201688a4716f53b8a335fc53569.camel@mihalicyn.com/)
> if Volker is going to continue his work on this, but received no reply so I
> just decided to go forward: take his patches, rebase and resend. Of course,
> I kept all authorship/tags so I hope that it is fine.
>
> Testing.
>
> I manually validated this with Ubuntu 24.04 Desktop VM and found no issues.
> Also, it was validated with CI (https://gitlab.com/mihalicyn/qemu/-/pipelines/2626702088).
>
> Original patchset:
> https://lore.kernel.org/qemu-devel/a289a081-9a61-4bcb-b693-bf6cd7768c0e@t-online.de [1]
>
> Git tree:
> https://gitlab.com/mihalicyn/qemu/-/commits/virtio-sound-migration
>
> Changelog for version 3:
> - addressed review feedback from Marc-André Lureau:
> - drop VirtIOSoundPCMStream's id field (unused)
> - resurrected error_report(..) in virtio_snd_pcm_start_stop()
> - fixes in "hw/audio/virtio-sound: add stream state variable"
> [ please, look in commit message for details ]
> - added "hw/audio/virtio-sound: remove channel positions field
> from VirtIOSoundPCMStream"
> - fixes in "hw/audio/virtio-sound: add missing vmstate fields"
> [ details in commit message ]
>
> Changelog for version 2:
> - no code changes (only commit messages)
> followed suggestions from Daniel P. Berrangé (thanks, Daniel!)
> https://lore.kernel.org/qemu-devel/ajzoxZr4g0Xsr_4p@redhat.com/
> and added some extra details about what I did with the original
> patches during rebase (for some of them it was simpler and less error
> prone to just drop changes and reimplement them by following the idea
> of the patch, cause base code has changed significantly).
>
> Changelog relative to the original Volker Rümelin's submission:
> - rebased:
> - "hw/audio/virtio-sound: return correct command response size"
> was dropped as it was already merged
> - "hw/audio/virtio-sound: fix segmentation fault in tx/rx xfer handler"
> was dropped as it seems to be replaced with another fix
> https://github.com/qemu/qemu/commit/731655f87f319fd06f27282c6cafbc2467ac8045
> - I had to drop all pre-existing Reviewed-by tags cause it was 2 years since
> this patchset was sent and reviewed and I did a quite significant code changes
> during rebase
>
> Kind regards,
> Alex
>
> Alexander Mikhalitsyn (1):
> hw/audio/virtio-sound: remove channel positions field from
> VirtIOSoundPCMStream
>
> Volker Rümelin (8):
> hw/audio/virtio-sound: remove command and stream mutexes
> hw/audio/virtio-sound: allocate an array of streams
> hw/audio/virtio-sound: free all stream buffers on reset
> hw/audio/virtio-sound: split out virtio_snd_pcm_start_stop()
> hw/audio/virtio-sound: add stream state variable
> hw/audio/virtio-sound: introduce virtio_snd_pcm_open()
> hw/audio/virtio-sound: introduce virtio_snd_set_active()
> hw/audio/virtio-sound: add missing vmstate fields
>
> hw/audio/trace-events | 3 +-
> hw/audio/virtio-snd.c | 679 ++++++++++++++++++++--------------
> include/hw/audio/virtio-snd.h | 26 +-
> 3 files changed, 399 insertions(+), 309 deletions(-)
>
> --
> 2.47.3
>
--
Manos Pitsidianakis
Emulation and Virtualization Engineer at Linaro Ltd
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support
2026-06-29 11:04 ` [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support Manos Pitsidianakis
@ 2026-06-29 11:32 ` Aleksandr Mikhalitsyn
2026-06-29 12:01 ` Manos Pitsidianakis
0 siblings, 1 reply; 26+ messages in thread
From: Aleksandr Mikhalitsyn @ 2026-06-29 11:32 UTC (permalink / raw)
To: Manos Pitsidianakis, Alexander Mikhalitsyn
Cc: qemu-devel@nongnu.org, Volker Rümelin,
Marc-André Lureau, Stéphane Graber,
Daniel P . Berrangé, Gerd Hoffmann, Michael S. Tsirkin
[-- Attachment #1: Type: text/plain, Size: 5837 bytes --]
Dear Manos,
(replying from my @futurfusion.io address)
I'm using my personal email address hosted at Gmail, cause it works just well with plain text email and does not corrupt patches.
While Microsoft Outlook (behind futurfusion.io) doesn't work that good, so I still do SoB tags with my work email, but send
them through Gmail servers. Hope it is fine.
I'm ready to do all necessary actions to proof that these two email belong to me, for example I send my series from
my Gmail and then reply from futurfusion.io with some ACK to prove that it's me.
Also, in Linux kernel I have a proper email mapping:
https://github.com/torvalds/linux/blob/dc59e4fea9d83f03bad6bddf3fa2e52491777482/.mailmap#L38
P.S. Sorry for doing non-inline reply, it's again because of terrible Outlook.
P.S.2. I'll continue my work on patches next week, cause I'm currently away from home on vacation. ;)
Huge thanks for such a fast review of my patch submission!
Kind regards,
Alex
________________________________
From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Sent: Monday, June 29, 2026 13:04
To: Alexander Mikhalitsyn <alexander@mihalicyn.com>
Cc: qemu-devel@nongnu.org <qemu-devel@nongnu.org>; Volker Rümelin <vr_qemu@t-online.de>; Marc-André Lureau <marcandre.lureau@redhat.com>; Stéphane Graber <stgraber@stgraber.org>; Daniel P . Berrangé <berrange@redhat.com>; Gerd Hoffmann <kraxel@redhat.com>; Michael S. Tsirkin <mst@redhat.com>; Aleksandr Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
Subject: Re: [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support
Hi Alexander,
On Fri, Jun 26, 2026 at 3:35 PM Alexander Mikhalitsyn
<alexander@mihalicyn.com> wrote:
>
> From: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
Could you please send your patches from your
aleksandr.mikhalitsyn@futurfusion.io address for the next revision?
Replying to review comments with your personal email is fine, but the
s-o-b should match your sending address. We do not know if the address
belongs to you otherwise. This is not explicitly stated in our Code
Provenance documentation but we need a way to verify your S-o-b
provenance.
Thanks,
>
> Dear friends,
>
> This patchset is aimed to support virtio-sound live migration and based on
> pre-existing Volker Rümelin's patches from qemu-devel lists [1]. I tried
> to ask (https://lore.kernel.org/qemu-devel/9d7ea128c711c201688a4716f53b8a335fc53569.camel@mihalicyn.com/)
> if Volker is going to continue his work on this, but received no reply so I
> just decided to go forward: take his patches, rebase and resend. Of course,
> I kept all authorship/tags so I hope that it is fine.
>
> Testing.
>
> I manually validated this with Ubuntu 24.04 Desktop VM and found no issues.
> Also, it was validated with CI (https://gitlab.com/mihalicyn/qemu/-/pipelines/2626702088).
>
> Original patchset:
> https://lore.kernel.org/qemu-devel/a289a081-9a61-4bcb-b693-bf6cd7768c0e@t-online.de [1]
>
> Git tree:
> https://gitlab.com/mihalicyn/qemu/-/commits/virtio-sound-migration
>
> Changelog for version 3:
> - addressed review feedback from Marc-André Lureau:
> - drop VirtIOSoundPCMStream's id field (unused)
> - resurrected error_report(..) in virtio_snd_pcm_start_stop()
> - fixes in "hw/audio/virtio-sound: add stream state variable"
> [ please, look in commit message for details ]
> - added "hw/audio/virtio-sound: remove channel positions field
> from VirtIOSoundPCMStream"
> - fixes in "hw/audio/virtio-sound: add missing vmstate fields"
> [ details in commit message ]
>
> Changelog for version 2:
> - no code changes (only commit messages)
> followed suggestions from Daniel P. Berrangé (thanks, Daniel!)
> https://lore.kernel.org/qemu-devel/ajzoxZr4g0Xsr_4p@redhat.com/
> and added some extra details about what I did with the original
> patches during rebase (for some of them it was simpler and less error
> prone to just drop changes and reimplement them by following the idea
> of the patch, cause base code has changed significantly).
>
> Changelog relative to the original Volker Rümelin's submission:
> - rebased:
> - "hw/audio/virtio-sound: return correct command response size"
> was dropped as it was already merged
> - "hw/audio/virtio-sound: fix segmentation fault in tx/rx xfer handler"
> was dropped as it seems to be replaced with another fix
> https://github.com/qemu/qemu/commit/731655f87f319fd06f27282c6cafbc2467ac8045
> - I had to drop all pre-existing Reviewed-by tags cause it was 2 years since
> this patchset was sent and reviewed and I did a quite significant code changes
> during rebase
>
> Kind regards,
> Alex
>
> Alexander Mikhalitsyn (1):
> hw/audio/virtio-sound: remove channel positions field from
> VirtIOSoundPCMStream
>
> Volker Rümelin (8):
> hw/audio/virtio-sound: remove command and stream mutexes
> hw/audio/virtio-sound: allocate an array of streams
> hw/audio/virtio-sound: free all stream buffers on reset
> hw/audio/virtio-sound: split out virtio_snd_pcm_start_stop()
> hw/audio/virtio-sound: add stream state variable
> hw/audio/virtio-sound: introduce virtio_snd_pcm_open()
> hw/audio/virtio-sound: introduce virtio_snd_set_active()
> hw/audio/virtio-sound: add missing vmstate fields
>
> hw/audio/trace-events | 3 +-
> hw/audio/virtio-snd.c | 679 ++++++++++++++++++++--------------
> include/hw/audio/virtio-snd.h | 26 +-
> 3 files changed, 399 insertions(+), 309 deletions(-)
>
> --
> 2.47.3
>
--
Manos Pitsidianakis
Emulation and Virtualization Engineer at Linaro Ltd
[-- Attachment #2: Type: text/html, Size: 13283 bytes --]
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 0/9] hw/audio/virtio-sound: basic migration support
2026-06-29 11:32 ` Aleksandr Mikhalitsyn
@ 2026-06-29 12:01 ` Manos Pitsidianakis
0 siblings, 0 replies; 26+ messages in thread
From: Manos Pitsidianakis @ 2026-06-29 12:01 UTC (permalink / raw)
To: Aleksandr Mikhalitsyn
Cc: Alexander Mikhalitsyn,
open list:ARM SMMU <qemu-arm@nongnu.org>, ,
Volker Rümelin, Marc-André Lureau, Stéphane Graber,
Daniel P . Berrangé, Gerd Hoffmann, Michael S. Tsirkin
[-- Attachment #1: Type: text/plain, Size: 6366 bytes --]
On Mon, 29 Jun 2026, 14:32 Aleksandr Mikhalitsyn, <
aleksandr.mikhalitsyn@futurfusion.io> wrote:
> Dear Manos,
>
> (replying from my @futurfusion.io address)
>
> I'm using my personal email address hosted at Gmail, cause it works just
> well with plain text email and does not corrupt patches.
> While Microsoft Outlook (behind futurfusion.io) doesn't work that good,
> so I still do SoB tags with my work email, but send
> them through Gmail servers. Hope it is fine.
>
Ok, that is good enough proof for me! No need to do anything different then
for future revisions.
> I'm ready to do all necessary actions to proof that these two email belong
> to me, for example I send my series from
> my Gmail and then reply from futurfusion.io with some ACK to prove that
> it's me.
>
> Also, in Linux kernel I have a proper email mapping:
>
> https://github.com/torvalds/linux/blob/dc59e4fea9d83f03bad6bddf3fa2e52491777482/.mailmap#L38
>
> P.S. Sorry for doing non-inline reply, it's again because of terrible
> Outlook.
>
> P.S.2. I'll continue my work on patches next week, cause I'm currently
> away from home on vacation. ;)
> Huge thanks for such a fast review of my patch submission!
>
> Kind regards,
> Alex
>
> ------------------------------
> *From:* Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
> *Sent:* Monday, June 29, 2026 13:04
> *To:* Alexander Mikhalitsyn <alexander@mihalicyn.com>
> *Cc:* qemu-devel@nongnu.org <qemu-devel@nongnu.org>; Volker Rümelin <
> vr_qemu@t-online.de>; Marc-André Lureau <marcandre.lureau@redhat.com>;
> Stéphane Graber <stgraber@stgraber.org>; Daniel P . Berrangé <
> berrange@redhat.com>; Gerd Hoffmann <kraxel@redhat.com>; Michael S.
> Tsirkin <mst@redhat.com>; Aleksandr Mikhalitsyn <
> aleksandr.mikhalitsyn@futurfusion.io>
> *Subject:* Re: [PATCH v3 0/9] hw/audio/virtio-sound: basic migration
> support
>
> Hi Alexander,
>
> On Fri, Jun 26, 2026 at 3:35 PM Alexander Mikhalitsyn
> <alexander@mihalicyn.com> wrote:
> >
> > From: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
>
> Could you please send your patches from your
> aleksandr.mikhalitsyn@futurfusion.io address for the next revision?
> Replying to review comments with your personal email is fine, but the
> s-o-b should match your sending address. We do not know if the address
> belongs to you otherwise. This is not explicitly stated in our Code
> Provenance documentation but we need a way to verify your S-o-b
> provenance.
>
> Thanks,
>
> >
> > Dear friends,
> >
> > This patchset is aimed to support virtio-sound live migration and based
> on
> > pre-existing Volker Rümelin's patches from qemu-devel lists [1]. I tried
> > to ask (
> https://lore.kernel.org/qemu-devel/9d7ea128c711c201688a4716f53b8a335fc53569.camel@mihalicyn.com/
> )
> > if Volker is going to continue his work on this, but received no reply
> so I
> > just decided to go forward: take his patches, rebase and resend. Of
> course,
> > I kept all authorship/tags so I hope that it is fine.
> >
> > Testing.
> >
> > I manually validated this with Ubuntu 24.04 Desktop VM and found no
> issues.
> > Also, it was validated with CI (
> https://gitlab.com/mihalicyn/qemu/-/pipelines/2626702088).
> >
> > Original patchset:
> >
> https://lore.kernel.org/qemu-devel/a289a081-9a61-4bcb-b693-bf6cd7768c0e@t-online.de
> [1]
> >
> > Git tree:
> > https://gitlab.com/mihalicyn/qemu/-/commits/virtio-sound-migration
> >
> > Changelog for version 3:
> > - addressed review feedback from Marc-André Lureau:
> > - drop VirtIOSoundPCMStream's id field (unused)
> > - resurrected error_report(..) in virtio_snd_pcm_start_stop()
> > - fixes in "hw/audio/virtio-sound: add stream state variable"
> > [ please, look in commit message for details ]
> > - added "hw/audio/virtio-sound: remove channel positions field
> > from VirtIOSoundPCMStream"
> > - fixes in "hw/audio/virtio-sound: add missing vmstate fields"
> > [ details in commit message ]
> >
> > Changelog for version 2:
> > - no code changes (only commit messages)
> > followed suggestions from Daniel P. Berrangé (thanks, Daniel!)
> > https://lore.kernel.org/qemu-devel/ajzoxZr4g0Xsr_4p@redhat.com/
> > and added some extra details about what I did with the original
> > patches during rebase (for some of them it was simpler and less error
> > prone to just drop changes and reimplement them by following the idea
> > of the patch, cause base code has changed significantly).
> >
> > Changelog relative to the original Volker Rümelin's submission:
> > - rebased:
> > - "hw/audio/virtio-sound: return correct command response size"
> > was dropped as it was already merged
> > - "hw/audio/virtio-sound: fix segmentation fault in tx/rx xfer
> handler"
> > was dropped as it seems to be replaced with another fix
> >
> https://github.com/qemu/qemu/commit/731655f87f319fd06f27282c6cafbc2467ac8045
> > - I had to drop all pre-existing Reviewed-by tags cause it was 2
> years since
> > this patchset was sent and reviewed and I did a quite
> significant code changes
> > during rebase
> >
> > Kind regards,
> > Alex
> >
> > Alexander Mikhalitsyn (1):
> > hw/audio/virtio-sound: remove channel positions field from
> > VirtIOSoundPCMStream
> >
> > Volker Rümelin (8):
> > hw/audio/virtio-sound: remove command and stream mutexes
> > hw/audio/virtio-sound: allocate an array of streams
> > hw/audio/virtio-sound: free all stream buffers on reset
> > hw/audio/virtio-sound: split out virtio_snd_pcm_start_stop()
> > hw/audio/virtio-sound: add stream state variable
> > hw/audio/virtio-sound: introduce virtio_snd_pcm_open()
> > hw/audio/virtio-sound: introduce virtio_snd_set_active()
> > hw/audio/virtio-sound: add missing vmstate fields
> >
> > hw/audio/trace-events | 3 +-
> > hw/audio/virtio-snd.c | 679 ++++++++++++++++++++--------------
> > include/hw/audio/virtio-snd.h | 26 +-
> > 3 files changed, 399 insertions(+), 309 deletions(-)
> >
> > --
> > 2.47.3
> >
>
> --
> Manos Pitsidianakis
> Emulation and Virtualization Engineer at Linaro Ltd
>
[-- Attachment #2: Type: text/html, Size: 13730 bytes --]
^ permalink raw reply [flat|nested] 26+ messages in thread