ALSA: xen-front: Use Xen common shared buffer implementation

Use page directory based shared buffer implementation
now available as common code for Xen frontend drivers.

Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
This commit is contained in:
Oleksandr Andrushchenko
2018-11-30 09:42:05 +02:00
zatwierdzone przez Boris Ostrovsky
rodzic 5641f19bdf
commit 58f9d806d1
7 zmienionych plików z 84 dodań i 261 usunięć

Wyświetl plik

@@ -15,17 +15,24 @@
#include <sound/pcm_params.h>
#include <xen/xenbus.h>
#include <xen/xen-front-pgdir-shbuf.h>
#include "xen_snd_front.h"
#include "xen_snd_front_alsa.h"
#include "xen_snd_front_cfg.h"
#include "xen_snd_front_evtchnl.h"
#include "xen_snd_front_shbuf.h"
struct xen_snd_front_pcm_stream_info {
struct xen_snd_front_info *front_info;
struct xen_snd_front_evtchnl_pair *evt_pair;
struct xen_snd_front_shbuf sh_buf;
/* This is the shared buffer with its backing storage. */
struct xen_front_pgdir_shbuf shbuf;
u8 *buffer;
size_t buffer_sz;
int num_pages;
struct page **pages;
int index;
bool is_open;
@@ -214,12 +221,20 @@ static void stream_clear(struct xen_snd_front_pcm_stream_info *stream)
stream->out_frames = 0;
atomic_set(&stream->hw_ptr, 0);
xen_snd_front_evtchnl_pair_clear(stream->evt_pair);
xen_snd_front_shbuf_clear(&stream->sh_buf);
memset(&stream->shbuf, 0, sizeof(stream->shbuf));
stream->buffer = NULL;
stream->buffer_sz = 0;
stream->pages = NULL;
stream->num_pages = 0;
}
static void stream_free(struct xen_snd_front_pcm_stream_info *stream)
{
xen_snd_front_shbuf_free(&stream->sh_buf);
xen_front_pgdir_shbuf_unmap(&stream->shbuf);
xen_front_pgdir_shbuf_free(&stream->shbuf);
if (stream->buffer)
free_pages_exact(stream->buffer, stream->buffer_sz);
kfree(stream->pages);
stream_clear(stream);
}
@@ -421,10 +436,34 @@ static int alsa_close(struct snd_pcm_substream *substream)
return 0;
}
static int shbuf_setup_backstore(struct xen_snd_front_pcm_stream_info *stream,
size_t buffer_sz)
{
int i;
stream->buffer = alloc_pages_exact(stream->buffer_sz, GFP_KERNEL);
if (!stream->buffer)
return -ENOMEM;
stream->buffer_sz = buffer_sz;
stream->num_pages = DIV_ROUND_UP(stream->buffer_sz, PAGE_SIZE);
stream->pages = kcalloc(stream->num_pages, sizeof(struct page *),
GFP_KERNEL);
if (!stream->pages)
return -ENOMEM;
for (i = 0; i < stream->num_pages; i++)
stream->pages[i] = virt_to_page(stream->buffer + i * PAGE_SIZE);
return 0;
}
static int alsa_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
struct xen_snd_front_info *front_info = stream->front_info;
struct xen_front_pgdir_shbuf_cfg buf_cfg;
int ret;
/*
@@ -432,19 +471,32 @@ static int alsa_hw_params(struct snd_pcm_substream *substream,
* so free the previously allocated shared buffer if any.
*/
stream_free(stream);
ret = shbuf_setup_backstore(stream, params_buffer_bytes(params));
if (ret < 0)
goto fail;
ret = xen_snd_front_shbuf_alloc(stream->front_info->xb_dev,
&stream->sh_buf,
params_buffer_bytes(params));
if (ret < 0) {
stream_free(stream);
dev_err(&stream->front_info->xb_dev->dev,
"Failed to allocate buffers for stream with index %d\n",
stream->index);
return ret;
}
memset(&buf_cfg, 0, sizeof(buf_cfg));
buf_cfg.xb_dev = front_info->xb_dev;
buf_cfg.pgdir = &stream->shbuf;
buf_cfg.num_pages = stream->num_pages;
buf_cfg.pages = stream->pages;
ret = xen_front_pgdir_shbuf_alloc(&buf_cfg);
if (ret < 0)
goto fail;
ret = xen_front_pgdir_shbuf_map(&stream->shbuf);
if (ret < 0)
goto fail;
return 0;
fail:
stream_free(stream);
dev_err(&front_info->xb_dev->dev,
"Failed to allocate buffers for stream with index %d\n",
stream->index);
return ret;
}
static int alsa_hw_free(struct snd_pcm_substream *substream)
@@ -476,7 +528,7 @@ static int alsa_prepare(struct snd_pcm_substream *substream)
sndif_format = ret;
ret = xen_snd_front_stream_prepare(&stream->evt_pair->req,
&stream->sh_buf,
&stream->shbuf,
sndif_format,
runtime->channels,
runtime->rate,
@@ -556,10 +608,10 @@ static int alsa_pb_copy_user(struct snd_pcm_substream *substream,
{
struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
if (unlikely(pos + count > stream->sh_buf.buffer_sz))
if (unlikely(pos + count > stream->buffer_sz))
return -EINVAL;
if (copy_from_user(stream->sh_buf.buffer + pos, src, count))
if (copy_from_user(stream->buffer + pos, src, count))
return -EFAULT;
return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count);
@@ -571,10 +623,10 @@ static int alsa_pb_copy_kernel(struct snd_pcm_substream *substream,
{
struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
if (unlikely(pos + count > stream->sh_buf.buffer_sz))
if (unlikely(pos + count > stream->buffer_sz))
return -EINVAL;
memcpy(stream->sh_buf.buffer + pos, src, count);
memcpy(stream->buffer + pos, src, count);
return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count);
}
@@ -586,14 +638,14 @@ static int alsa_cap_copy_user(struct snd_pcm_substream *substream,
struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
int ret;
if (unlikely(pos + count > stream->sh_buf.buffer_sz))
if (unlikely(pos + count > stream->buffer_sz))
return -EINVAL;
ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count);
if (ret < 0)
return ret;
return copy_to_user(dst, stream->sh_buf.buffer + pos, count) ?
return copy_to_user(dst, stream->buffer + pos, count) ?
-EFAULT : 0;
}
@@ -604,14 +656,14 @@ static int alsa_cap_copy_kernel(struct snd_pcm_substream *substream,
struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
int ret;
if (unlikely(pos + count > stream->sh_buf.buffer_sz))
if (unlikely(pos + count > stream->buffer_sz))
return -EINVAL;
ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count);
if (ret < 0)
return ret;
memcpy(dst, stream->sh_buf.buffer + pos, count);
memcpy(dst, stream->buffer + pos, count);
return 0;
}
@@ -622,10 +674,10 @@ static int alsa_pb_fill_silence(struct snd_pcm_substream *substream,
{
struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
if (unlikely(pos + count > stream->sh_buf.buffer_sz))
if (unlikely(pos + count > stream->buffer_sz))
return -EINVAL;
memset(stream->sh_buf.buffer + pos, 0, count);
memset(stream->buffer + pos, 0, count);
return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count);
}