Linux Sound subsystem development
 help / color / mirror / Atom feed
From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
To: Jaroslav Kysela <perex@perex.cz>, linux-sound@vger.kernel.org
Cc: "Takashi Iwai" <tiwai@suse.de>, "Mark Brown" <broonie@kernel.org>,
	"Shengjiu Wang" <shengjiu.wang@gmail.com>,
	"Nicolas Dufresne" <nicolas@ndufresne.ca>,
	"Amadeusz Sławiński" <amadeuszx.slawinski@linux.intel.com>,
	"Vinod Koul" <vkoul@kernel.org>
Subject: Re: [PATCH v3] ALSA: compress_offload: introduce passthrough operation mode
Date: Mon, 24 Jun 2024 09:13:09 +0200	[thread overview]
Message-ID: <18c2a323-f0b5-4dea-b502-ce7e7021c555@linux.intel.com> (raw)
In-Reply-To: <20240621164915.410946-1-perex@perex.cz>

Thanks Jaroslav, couple of questions below:

> +For the buffering parameters, the fragments means a limit of allocated tasks
> +for given device. The fragment_size limits the input buffer size for the given
> +device. The output buffer size is determined by the driver (may be different
> +from the input buffer size).

if (stream->direction == SND_COMPRESS_PASSTHROUGH)
	max_fragments = 64;			/* safe value */

Is there anything preventing us from increasing this if there was a need
for it? Wondering if this would be an ABI restriction or just an
internal safeguard userspace doesn't need to know.

> +
> +State Machine
> +=============
> +
> +The passthrough audio stream state machine is described below :
> +
> +                                       +----------+
> +                                       |          |
> +                                       |   OPEN   |
> +                                       |          |
> +                                       +----------+
> +                                             |
> +                                             |
> +                                             | compr_set_params()
> +                                             |
> +                                             v
> +         all passthrough task ops      +----------+
> +  +------------------------------------|          |
> +  |                                    |   SETUP  |
> +  |                                    |
> +  |                                    +----------+
> +  |                                          |
> +  +------------------------------------------+
> +
> +
> +Passthrough operations (ioctls)
> +===============================
> +
> +CREATE
> +------
> +Creates a set of input/output buffers. The input buffer size is
> +fragment_size. Allocates unique seqno.
> +
> +The hardware drivers allocate internal 'struct dma_buf' for both input and
> +output buffers (using 'dma_buf_export()' function). The anonymous
> +file descriptors for those buffers are passed to user space.

The code adds the tasks in the order in which they are created:

	list_add_tail(&task->list, &stream->runtime->tasks);

This should probably be documented, there's no explicit mechanism to
chain the tasks other than the order of creation.

> +FREE
> +----
> +Free a set of input/output buffers. If a task is active, the stop
> +operation is executed before. If seqno is zero, operation is executed for all
> +tasks.

Can a task in the middle of the list be freed?

If yes, is any locking required?

> +START
> +-----
> +Starts (queues) a task. There are two cases of the task start - right after
> +the task is created. In this case, origin_seqno must be zero.
> +The second case is for reusing of already finished task. The origin_seqno
> +must identify the task to be reused. In both cases, a new seqno value
> +is allocated and returned to user space.
> +
> +The prerequisite is that application filled input dma buffer with
> +new source data and set input_size to pass the real data size to the driver.
> +
> +The order of data processing is preserved (first started job must be
> +finished at first).
> +
> +STOP
> +----
> +Stop (dequeues) a task. If seqno is zero, operation is executed for all
> +tasks.

What happens if a STOP is sent to a task in the middle of the list?


It's similar to the question on free above, the creation needs to follow
an order but the free/stop can be individual tasks so there could be
interesting state machine transition and programming errors.

I honestly find the state machine confusing, it looks like in the SETUP
stage tasks can be added/removed dynamically, but I am not sure if it's
a real use case? Most pipeline management add a bunch of processing,
then go in the 'run' mode. Adding/removing stuff on a running pipeline
is really painful and not super useful, is it?

>  /**
>   * struct snd_compr_runtime: runtime stream description
>   * @state: stream state
> @@ -54,6 +70,11 @@ struct snd_compr_runtime {
>  	dma_addr_t dma_addr;
>  	size_t dma_bytes;
>  	struct snd_dma_buffer *dma_buffer_p;
> +
> +	u32 active_tasks;
> +	u32 total_tasks;
> +	u64 task_seqno;
> +	struct list_head tasks;
>  };

should there be some sort of identifier that says the stream in used in
passthrough mode and only then are the 4 added members relevant?


'struct snd_compr_runtime' doesn't have a notion of direction, so
there's no real way to know what set_params() requested.

> diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h
> index d185957f3fe0..5fed1979522b 100644
> --- a/include/uapi/sound/compress_offload.h
> +++ b/include/uapi/sound/compress_offload.h
> @@ -1,4 +1,4 @@
> -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> +	/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */

spurious change?

>  /*
>   *  compress_offload.h - compress offload header definations
>   *
> @@ -14,7 +14,7 @@

> +/**
> + * struct snd_compr_task - task primitive for non-realtime operation
> + * @seqno: sequence number (task identifier)
> + * @origin_seqno: previous sequence number (task identifier) - for reuse
> + * @input_fd: data input file descriptor (dma-buf)
> + * @output_fd: data output file descriptor (dma-buf)
> + * @input_size: filled data in bytes (from caller, must not exceed fragment size)
> + */
> +struct snd_compr_task {
> +	__u64 seqno;
> +	__u64 origin_seqno;
> +	int input_fd;
> +	int output_fd;
> +	__u64 input_size;

Any reason why output_size is not listed here....

> +	__u8 reserved[16];
> +} __attribute__((packed, aligned(4)));
> +
> +enum snd_compr_state {
> +	SND_COMPRESS_TASK_STATE_IDLE = 0,
> +	SND_COMPRESS_TASK_STATE_ACTIVE,
> +	SND_COMPRESS_TASK_STATE_FINISHED
> +};
> +
> +/**
> + * struct snd_compr_task_status - task status
> + * @seqno: sequence number (task identifier)
> + * @output_size: filled data in bytes (from driver)
> + * @state: actual task state (SND_COMPRESS_TASK_STATE_*)
> + */
> +struct snd_compr_task_status {
> +	__u64 seqno;
> +	__u64 output_size;

... but it's listed here.

It'd be worth explaining why the input and output are in different
structures. I can understand that for the configuration only the host
can provide data in the input, but in a status it'd be good to have a
snapshot of the two variables, no?


> +	__u8 state;
> +	__u8 reserved[15];
> +} __attribute__((packed, aligned(4)));

> +static int snd_compr_task_new(struct snd_compr_stream *stream, struct snd_compr_task *utask)
> +{
> +	struct snd_compr_task_runtime *task;
> +	int retval;
> +
> +	if (stream->runtime->total_tasks >= stream->runtime->fragments)
> +		return -EBUSY;
> +	if (utask->origin_seqno != 0 || utask->input_size != 0)
> +		return -EINVAL;
> +	task = kzalloc(sizeof(*task), GFP_KERNEL);
> +	if (task == NULL)
> +		return -ENOMEM;
> +	task->seqno = utask->seqno = snd_compr_seqno_next(stream);
> +	task->input_size = utask->input_size;
> +	retval = stream->ops->task_create(stream, task);
> +	if (retval < 0)
> +		goto cleanup;
> +	utask->input_fd = dma_buf_fd(task->input, O_WRONLY|O_CLOEXEC);
> +	if (utask->input_fd < 0) {
> +		retval = utask->input_fd;
> +		goto cleanup;
> +	}
> +	utask->output_fd = dma_buf_fd(task->output, O_RDONLY|O_CLOEXEC);
> +	if (utask->output_fd < 0) {
> +		retval = utask->output_fd;
> +		goto cleanup;
> +	}
> +	/* keep dmabuf reference until freed with task free ioctl */
> +	dma_buf_get(utask->input_fd);
> +	dma_buf_get(utask->output_fd);
> +	list_add_tail(&task->list, &stream->runtime->tasks);
> +	stream->runtime->total_tasks++;

no locking for these two lines? If there's already a lock handled by the
ALSA/ASoC/compressed frameworks, it'd be worth explaining which one is
assumed to be held.

> +	return 0;
> +cleanup:
> +	snd_compr_task_free(task);
> +	return retval;
> +}


  reply	other threads:[~2024-06-24 15:28 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-21 16:49 [PATCH v3] ALSA: compress_offload: introduce passthrough operation mode Jaroslav Kysela
2024-06-24  7:13 ` Pierre-Louis Bossart [this message]
2024-06-24 15:58   ` Jaroslav Kysela
2024-06-25  6:06     ` Pierre-Louis Bossart
2024-06-25 11:48       ` Jaroslav Kysela
2024-06-25 12:36         ` Pierre-Louis Bossart
2024-06-25 13:00           ` Jaroslav Kysela
2024-06-25 13:48             ` Pierre-Louis Bossart
2024-06-24 13:19 ` Takashi Iwai
2024-06-24 13:59   ` Jaroslav Kysela
2024-06-25  1:58 ` Shengjiu Wang

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=18c2a323-f0b5-4dea-b502-ce7e7021c555@linux.intel.com \
    --to=pierre-louis.bossart@linux.intel.com \
    --cc=amadeuszx.slawinski@linux.intel.com \
    --cc=broonie@kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=nicolas@ndufresne.ca \
    --cc=perex@perex.cz \
    --cc=shengjiu.wang@gmail.com \
    --cc=tiwai@suse.de \
    --cc=vkoul@kernel.org \
    /path/to/YOUR_REPLY

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

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