Skip to content

Commit

Permalink
ALSA: xen-front: Use Xen common shared buffer implementation
Browse files Browse the repository at this point in the history
Use page directory based shared buffer implementation
now available as common code for Xen frontend drivers.

Signed-off-by: Oleksandr Andrushchenko <[email protected]>
Reviewed-by: Takashi Iwai <[email protected]>
Signed-off-by: Boris Ostrovsky <[email protected]>
  • Loading branch information
Oleksandr Andrushchenko authored and Boris Ostrovsky committed Dec 18, 2018
1 parent 5641f19 commit 58f9d80
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 261 deletions.
1 change: 1 addition & 0 deletions sound/xen/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ config SND_XEN_FRONTEND
depends on XEN
select SND_PCM
select XEN_XENBUS_FRONTEND
select XEN_FRONT_PGDIR_SHBUF
help
Choose this option if you want to enable a para-virtualized
frontend sound driver for Xen guest OSes.
1 change: 0 additions & 1 deletion sound/xen/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
snd_xen_front-objs := xen_snd_front.o \
xen_snd_front_cfg.o \
xen_snd_front_evtchnl.o \
xen_snd_front_shbuf.o \
xen_snd_front_alsa.o

obj-$(CONFIG_SND_XEN_FRONTEND) += snd_xen_front.o
7 changes: 4 additions & 3 deletions sound/xen/xen_snd_front.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
#include <xen/xen.h>
#include <xen/xenbus.h>

#include <xen/xen-front-pgdir-shbuf.h>
#include <xen/interface/io/sndif.h>

#include "xen_snd_front.h"
#include "xen_snd_front_alsa.h"
#include "xen_snd_front_evtchnl.h"
#include "xen_snd_front_shbuf.h"

static struct xensnd_req *
be_stream_prepare_req(struct xen_snd_front_evtchnl *evtchnl, u8 operation)
Expand Down Expand Up @@ -82,7 +82,7 @@ int xen_snd_front_stream_query_hw_param(struct xen_snd_front_evtchnl *evtchnl,
}

int xen_snd_front_stream_prepare(struct xen_snd_front_evtchnl *evtchnl,
struct xen_snd_front_shbuf *sh_buf,
struct xen_front_pgdir_shbuf *shbuf,
u8 format, unsigned int channels,
unsigned int rate, u32 buffer_sz,
u32 period_sz)
Expand All @@ -99,7 +99,8 @@ int xen_snd_front_stream_prepare(struct xen_snd_front_evtchnl *evtchnl,
req->op.open.pcm_rate = rate;
req->op.open.buffer_sz = buffer_sz;
req->op.open.period_sz = period_sz;
req->op.open.gref_directory = xen_snd_front_shbuf_get_dir_start(sh_buf);
req->op.open.gref_directory =
xen_front_pgdir_shbuf_get_dir_start(shbuf);
mutex_unlock(&evtchnl->ring_io_lock);

ret = be_stream_do_io(evtchnl);
Expand Down
4 changes: 2 additions & 2 deletions sound/xen/xen_snd_front.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
struct xen_snd_front_card_info;
struct xen_snd_front_evtchnl;
struct xen_snd_front_evtchnl_pair;
struct xen_snd_front_shbuf;
struct xen_front_pgdir_shbuf;
struct xensnd_query_hw_param;

struct xen_snd_front_info {
Expand All @@ -35,7 +35,7 @@ int xen_snd_front_stream_query_hw_param(struct xen_snd_front_evtchnl *evtchnl,
struct xensnd_query_hw_param *hw_param_resp);

int xen_snd_front_stream_prepare(struct xen_snd_front_evtchnl *evtchnl,
struct xen_snd_front_shbuf *sh_buf,
struct xen_front_pgdir_shbuf *shbuf,
u8 format, unsigned int channels,
unsigned int rate, u32 buffer_sz,
u32 period_sz);
Expand Down
102 changes: 77 additions & 25 deletions sound/xen/xen_snd_front_alsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -421,30 +436,67 @@ 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;

/*
* This callback may be called multiple times,
* 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)
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}
Expand All @@ -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;
}

Expand All @@ -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;
}
Expand All @@ -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);
}
Expand Down
Loading

0 comments on commit 58f9d80

Please sign in to comment.