Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/sound/soc-component.h
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ int snd_soc_component_compr_pointer(struct snd_compr_stream *cstream,
struct snd_compr_tstamp64 *tstamp);
int snd_soc_component_compr_copy(struct snd_compr_stream *cstream,
char __user *buf, size_t count);
int snd_soc_component_compr_mmap(struct snd_compr_stream *cstream,
struct vm_area_struct *vma);
int snd_soc_component_compr_set_metadata(struct snd_compr_stream *cstream,
struct snd_compr_metadata *metadata);
int snd_soc_component_compr_get_metadata(struct snd_compr_stream *cstream,
Expand Down
1 change: 1 addition & 0 deletions include/uapi/sound/compress_offload.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ struct snd_compr_task_status {
#define SNDRV_COMPRESS_AVAIL _IOR('C', 0x21, struct snd_compr_avail)
#define SNDRV_COMPRESS_TSTAMP64 _IOR('C', 0x22, struct snd_compr_tstamp64)
#define SNDRV_COMPRESS_AVAIL64 _IOR('C', 0x23, struct snd_compr_avail64)
#define SNDRV_COMPRESS_ACK _IOW('C', 0x24, __u64)
#define SNDRV_COMPRESS_PAUSE _IO('C', 0x30)
#define SNDRV_COMPRESS_RESUME _IO('C', 0x31)
#define SNDRV_COMPRESS_START _IO('C', 0x32)
Expand Down
72 changes: 72 additions & 0 deletions sound/core/compress_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <sound/compress_params.h>
#include <sound/compress_offload.h>
#include <sound/compress_driver.h>
#include <sound/memalloc.h>

/* struct snd_compr_codec_caps overflows the ioctl bit size for some
* architectures, so we need to disable the relevant ioctls.
Expand Down Expand Up @@ -310,6 +311,48 @@ static int snd_compr_ioctl_avail(struct snd_compr_stream *stream,
return 0;
}

static int snd_compr_ioctl_ack(struct snd_compr_stream *stream, unsigned long arg)
{
__u64 bytes;
size_t avail;
int ret = 0;

if (copy_from_user(&bytes, (void __user *)arg, sizeof(bytes)))
return -EFAULT;

if (bytes == 0)
return 0;

switch (stream->runtime->state) {
case SNDRV_PCM_STATE_SETUP:
case SNDRV_PCM_STATE_PREPARED:
case SNDRV_PCM_STATE_RUNNING:
break;
default:
return -EBADFD;
}

avail = snd_compr_get_avail(stream);
if (bytes > avail)
return -EINVAL;

if (stream->ops->ack) {
ret = stream->ops->ack(stream, bytes);
if (ret < 0)
return ret;
}

stream->runtime->total_bytes_available += bytes;

if (stream->runtime->state == SNDRV_PCM_STATE_SETUP) {
stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
pr_debug("stream prepared, Houston we are good to go\n");
}

wake_up(&stream->runtime->sleep);
return 0;
}

static int snd_compr_write_data(struct snd_compr_stream *stream,
const char __user *buf, size_t count)
{
Expand Down Expand Up @@ -439,6 +482,33 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,

static int snd_compr_mmap(struct file *f, struct vm_area_struct *vma)
{
struct snd_compr_file *data = f->private_data;
struct snd_compr_stream *stream;
struct snd_compr_runtime *runtime;

if (snd_BUG_ON(!data))
return -EINVAL;

stream = &data->stream;
runtime = stream->runtime;

if (!runtime)
return -ENODATA;

if (stream->direction == SND_COMPRESS_PLAYBACK) {
if (!(vma->vm_flags & (VM_WRITE | VM_READ)))
return -EINVAL;
} else {
if (!(vma->vm_flags & VM_READ))
return -EINVAL;
}

if (stream->ops->mmap)
return stream->ops->mmap(stream, vma);

if (runtime->dma_buffer_p)
return snd_dma_buffer_mmap(runtime->dma_buffer_p, vma);

return -ENXIO;
}

Expand Down Expand Up @@ -1383,6 +1453,8 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
return snd_compr_ioctl_avail(stream, arg, true);
case SNDRV_COMPRESS_AVAIL64:
return snd_compr_ioctl_avail(stream, arg, false);
case SNDRV_COMPRESS_ACK:
return snd_compr_ioctl_ack(stream, arg);
case SNDRV_COMPRESS_PAUSE:
return snd_compr_pause(stream);
case SNDRV_COMPRESS_RESUME:
Expand Down
24 changes: 24 additions & 0 deletions sound/soc/soc-component.c
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,30 @@ int snd_soc_component_compr_copy(struct snd_compr_stream *cstream,
}
EXPORT_SYMBOL_GPL(snd_soc_component_compr_copy);

int snd_soc_component_compr_mmap(struct snd_compr_stream *cstream,
struct vm_area_struct *vma)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_component *component;
int i, ret = -ENXIO;

snd_soc_dpcm_mutex_lock(rtd);

for_each_rtd_components(rtd, i, component) {
if (component->driver->compress_ops &&
component->driver->compress_ops->mmap) {
ret = component->driver->compress_ops->mmap(
component, cstream, vma);
break;
}
}

snd_soc_dpcm_mutex_unlock(rtd);

return soc_component_ret(component, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_component_compr_mmap);

int snd_soc_component_compr_set_metadata(struct snd_compr_stream *cstream,
struct snd_compr_metadata *metadata)
{
Expand Down
8 changes: 8 additions & 0 deletions sound/soc/soc-compress.c
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,12 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
return snd_soc_component_compr_get_metadata(cstream, metadata);
}

static int soc_compr_mmap(struct snd_compr_stream *cstream,
struct vm_area_struct *vma)
{
return snd_soc_component_compr_mmap(cstream, vma);
}

/* ASoC Compress operations */
static struct snd_compr_ops soc_compr_ops = {
.open = soc_compr_open,
Expand All @@ -668,6 +674,7 @@ static struct snd_compr_ops soc_compr_ops = {
.trigger = soc_compr_trigger,
.pointer = soc_compr_pointer,
.ack = soc_compr_ack,
.mmap = soc_compr_mmap,
.get_caps = snd_soc_component_compr_get_caps,
.get_codec_caps = snd_soc_component_compr_get_codec_caps,
};
Expand All @@ -683,6 +690,7 @@ static struct snd_compr_ops soc_compr_dyn_ops = {
.trigger = soc_compr_trigger_fe,
.pointer = soc_compr_pointer,
.ack = soc_compr_ack,
.mmap = soc_compr_mmap,
.get_caps = snd_soc_component_compr_get_caps,
.get_codec_caps = snd_soc_component_compr_get_codec_caps,
};
Expand Down
58 changes: 45 additions & 13 deletions sound/soc/sof/ipc4-compress.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <sound/sof.h>
#include <sound/compress_driver.h>
#include <sound/pcm_params.h>
#include <sound/memalloc.h>
#include "sof-audio.h"
#include "sof-priv.h"
#include "sof-utils.h"
Expand All @@ -14,8 +15,8 @@
#include "ipc4-topology.h"
#include "ipc4-fw-reg.h"

/* Maximum processing size of the decoder/encoder is 2048 bytes */
#define SOF_IPC4_COMPR_MAX_PROCESSING_SIZE (SZ_2K)
/* Minimum fragment size aligned to Intel HDA/ACE DMA burst hardware (128 bytes) */
#define SOF_IPC4_COMPR_MIN_FRAGMENT_SIZE (128)

#define SOF_IPC4_COMPR_MIN_FRAGMENTS 3
#define SOF_IPC4_COMPR_MAX_FRAGMENT_SIZE (SZ_128K)
Expand Down Expand Up @@ -58,10 +59,13 @@ static u32 sof_ipc4_compr_calc_min_fragment_size(struct snd_sof_pcm_stream *sps)
host_buffer_estimate = snd_pcm_format_size(SNDRV_PCM_FORMAT_S32_LE, 2 * 48);
host_buffer_estimate *= sps->dsp_max_burst_size_in_ms;
/*
* The minimum fragment size must not be smaller than the processing size
* or in case of deep buffer on host side, the host DMA buffer size.
* The minimum fragment size must align with HDA DMA burst boundary (128 bytes)
* or cover the deep buffer host DMA buffer size if configured.
*/
return max(SOF_IPC4_COMPR_MAX_PROCESSING_SIZE, host_buffer_estimate);
if (host_buffer_estimate)
return max_t(u32, SOF_IPC4_COMPR_MIN_FRAGMENT_SIZE, host_buffer_estimate);

return SOF_IPC4_COMPR_MIN_FRAGMENT_SIZE;
}

static int sof_ipc4_compr_open(struct snd_soc_component *component,
Expand Down Expand Up @@ -108,16 +112,18 @@ static int sof_ipc4_compr_stream_free(struct snd_sof_dev *sdev,
int err = 0;

if (spcm->prepared[dir]) {
if (spcm->pending_stop[dir])
if (spcm->pending_stop[dir] && pcm_ops && pcm_ops->trigger)
pcm_ops->trigger(sdev->component, NULL, spcm,
SNDRV_PCM_TRIGGER_STOP, dir);

snd_sof_compr_platform_trigger(sdev, cstream,
SNDRV_PCM_TRIGGER_STOP);

err = pcm_ops->hw_free(sdev->component, NULL, spcm, dir);
if (err < 0)
spcm_err(spcm, dir, "pcm_ops->hw_free failed %d\n", err);
if (pcm_ops && pcm_ops->hw_free) {
err = pcm_ops->hw_free(sdev->component, NULL, spcm, dir);
if (err < 0)
spcm_err(spcm, dir, "pcm_ops->hw_free failed %d\n", err);
}
}

spcm->prepared[dir] = false;
Expand Down Expand Up @@ -570,10 +576,12 @@ static int sof_ipc4_compr_trigger(struct snd_soc_component *component,

spcm_dbg(spcm, dir, "Entry: trigger (cmd: %d)\n", cmd);

ret = pcm_ops->trigger(component, NULL, spcm, cmd, dir);
if (ret < 0) {
spcm_err(spcm, dir, "pcm_ops->trigger failed for cmd %d\n", cmd);
return ret;
if (pcm_ops && pcm_ops->trigger) {
ret = pcm_ops->trigger(component, NULL, spcm, cmd, dir);
if (ret < 0) {
spcm_err(spcm, dir, "pcm_ops->trigger failed for cmd %d\n", cmd);
return ret;
}
}

if (!ret && trigger_platform) {
Expand Down Expand Up @@ -764,6 +772,28 @@ void sof_ipc4_compr_drain_done(struct snd_sof_dev *sdev, void *ipc_message)
snd_compr_drain_notify(spcm->stream[dir].cstream);
}

static int sof_ipc4_compr_mmap(struct snd_soc_component *component,
struct snd_compr_stream *stream,
struct vm_area_struct *vma)
{
struct snd_compr_runtime *runtime = stream->runtime;

if (!runtime || !runtime->dma_area)
return -ENXIO;

if (runtime->dma_buffer_p)
return snd_dma_buffer_mmap(runtime->dma_buffer_p, vma);

return snd_dma_buffer_mmap(&stream->dma_buffer, vma);
}

static int sof_ipc4_compr_ack(struct snd_soc_component *component,
struct snd_compr_stream *cstream,
size_t bytes)
{
return 0;
}

const struct snd_compress_ops sof_ipc4_compressed_ops = {
.open = sof_ipc4_compr_open,
.free = sof_ipc4_compr_free,
Expand All @@ -772,5 +802,7 @@ const struct snd_compress_ops sof_ipc4_compressed_ops = {
.get_params = sof_ipc4_compr_get_params,
.trigger = sof_ipc4_compr_trigger,
.pointer = sof_ipc4_compr_pointer,
.mmap = sof_ipc4_compr_mmap,
.ack = sof_ipc4_compr_ack,
.copy = sof_ipc4_compr_copy,
};
Loading