mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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:
		
							parent
							
								
									5641f19bdf
								
							
						
					
					
						commit
						58f9d806d1
					
				
					 7 changed files with 84 additions and 261 deletions
				
			
		| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,194 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0 OR MIT
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Xen para-virtual sound device
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2016-2018 EPAM Systems Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <xen/xen.h>
 | 
			
		||||
#include <xen/xenbus.h>
 | 
			
		||||
 | 
			
		||||
#include "xen_snd_front_shbuf.h"
 | 
			
		||||
 | 
			
		||||
grant_ref_t xen_snd_front_shbuf_get_dir_start(struct xen_snd_front_shbuf *buf)
 | 
			
		||||
{
 | 
			
		||||
	if (!buf->grefs)
 | 
			
		||||
		return GRANT_INVALID_REF;
 | 
			
		||||
 | 
			
		||||
	return buf->grefs[0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void xen_snd_front_shbuf_clear(struct xen_snd_front_shbuf *buf)
 | 
			
		||||
{
 | 
			
		||||
	memset(buf, 0, sizeof(*buf));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void xen_snd_front_shbuf_free(struct xen_snd_front_shbuf *buf)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (buf->grefs) {
 | 
			
		||||
		for (i = 0; i < buf->num_grefs; i++)
 | 
			
		||||
			if (buf->grefs[i] != GRANT_INVALID_REF)
 | 
			
		||||
				gnttab_end_foreign_access(buf->grefs[i],
 | 
			
		||||
							  0, 0UL);
 | 
			
		||||
		kfree(buf->grefs);
 | 
			
		||||
	}
 | 
			
		||||
	kfree(buf->directory);
 | 
			
		||||
	free_pages_exact(buf->buffer, buf->buffer_sz);
 | 
			
		||||
	xen_snd_front_shbuf_clear(buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * number of grant references a page can hold with respect to the
 | 
			
		||||
 * xensnd_page_directory header
 | 
			
		||||
 */
 | 
			
		||||
#define XENSND_NUM_GREFS_PER_PAGE ((XEN_PAGE_SIZE - \
 | 
			
		||||
		offsetof(struct xensnd_page_directory, gref)) / \
 | 
			
		||||
		sizeof(grant_ref_t))
 | 
			
		||||
 | 
			
		||||
static void fill_page_dir(struct xen_snd_front_shbuf *buf,
 | 
			
		||||
			  int num_pages_dir)
 | 
			
		||||
{
 | 
			
		||||
	struct xensnd_page_directory *page_dir;
 | 
			
		||||
	unsigned char *ptr;
 | 
			
		||||
	int i, cur_gref, grefs_left, to_copy;
 | 
			
		||||
 | 
			
		||||
	ptr = buf->directory;
 | 
			
		||||
	grefs_left = buf->num_grefs - num_pages_dir;
 | 
			
		||||
	/*
 | 
			
		||||
	 * skip grant references at the beginning, they are for pages granted
 | 
			
		||||
	 * for the page directory itself
 | 
			
		||||
	 */
 | 
			
		||||
	cur_gref = num_pages_dir;
 | 
			
		||||
	for (i = 0; i < num_pages_dir; i++) {
 | 
			
		||||
		page_dir = (struct xensnd_page_directory *)ptr;
 | 
			
		||||
		if (grefs_left <= XENSND_NUM_GREFS_PER_PAGE) {
 | 
			
		||||
			to_copy = grefs_left;
 | 
			
		||||
			page_dir->gref_dir_next_page = GRANT_INVALID_REF;
 | 
			
		||||
		} else {
 | 
			
		||||
			to_copy = XENSND_NUM_GREFS_PER_PAGE;
 | 
			
		||||
			page_dir->gref_dir_next_page = buf->grefs[i + 1];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		memcpy(&page_dir->gref, &buf->grefs[cur_gref],
 | 
			
		||||
		       to_copy * sizeof(grant_ref_t));
 | 
			
		||||
 | 
			
		||||
		ptr += XEN_PAGE_SIZE;
 | 
			
		||||
		grefs_left -= to_copy;
 | 
			
		||||
		cur_gref += to_copy;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int grant_references(struct xenbus_device *xb_dev,
 | 
			
		||||
			    struct xen_snd_front_shbuf *buf,
 | 
			
		||||
			    int num_pages_dir, int num_pages_buffer,
 | 
			
		||||
			    int num_grefs)
 | 
			
		||||
{
 | 
			
		||||
	grant_ref_t priv_gref_head;
 | 
			
		||||
	unsigned long frame;
 | 
			
		||||
	int ret, i, j, cur_ref;
 | 
			
		||||
	int otherend_id;
 | 
			
		||||
 | 
			
		||||
	ret = gnttab_alloc_grant_references(num_grefs, &priv_gref_head);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	buf->num_grefs = num_grefs;
 | 
			
		||||
	otherend_id = xb_dev->otherend_id;
 | 
			
		||||
	j = 0;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_pages_dir; i++) {
 | 
			
		||||
		cur_ref = gnttab_claim_grant_reference(&priv_gref_head);
 | 
			
		||||
		if (cur_ref < 0) {
 | 
			
		||||
			ret = cur_ref;
 | 
			
		||||
			goto fail;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		frame = xen_page_to_gfn(virt_to_page(buf->directory +
 | 
			
		||||
						     XEN_PAGE_SIZE * i));
 | 
			
		||||
		gnttab_grant_foreign_access_ref(cur_ref, otherend_id, frame, 0);
 | 
			
		||||
		buf->grefs[j++] = cur_ref;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_pages_buffer; i++) {
 | 
			
		||||
		cur_ref = gnttab_claim_grant_reference(&priv_gref_head);
 | 
			
		||||
		if (cur_ref < 0) {
 | 
			
		||||
			ret = cur_ref;
 | 
			
		||||
			goto fail;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		frame = xen_page_to_gfn(virt_to_page(buf->buffer +
 | 
			
		||||
						     XEN_PAGE_SIZE * i));
 | 
			
		||||
		gnttab_grant_foreign_access_ref(cur_ref, otherend_id, frame, 0);
 | 
			
		||||
		buf->grefs[j++] = cur_ref;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gnttab_free_grant_references(priv_gref_head);
 | 
			
		||||
	fill_page_dir(buf, num_pages_dir);
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
	gnttab_free_grant_references(priv_gref_head);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int alloc_int_buffers(struct xen_snd_front_shbuf *buf,
 | 
			
		||||
			     int num_pages_dir, int num_pages_buffer,
 | 
			
		||||
			     int num_grefs)
 | 
			
		||||
{
 | 
			
		||||
	buf->grefs = kcalloc(num_grefs, sizeof(*buf->grefs), GFP_KERNEL);
 | 
			
		||||
	if (!buf->grefs)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	buf->directory = kcalloc(num_pages_dir, XEN_PAGE_SIZE, GFP_KERNEL);
 | 
			
		||||
	if (!buf->directory)
 | 
			
		||||
		goto fail;
 | 
			
		||||
 | 
			
		||||
	buf->buffer_sz = num_pages_buffer * XEN_PAGE_SIZE;
 | 
			
		||||
	buf->buffer = alloc_pages_exact(buf->buffer_sz, GFP_KERNEL);
 | 
			
		||||
	if (!buf->buffer)
 | 
			
		||||
		goto fail;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
	kfree(buf->grefs);
 | 
			
		||||
	buf->grefs = NULL;
 | 
			
		||||
	kfree(buf->directory);
 | 
			
		||||
	buf->directory = NULL;
 | 
			
		||||
	return -ENOMEM;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int xen_snd_front_shbuf_alloc(struct xenbus_device *xb_dev,
 | 
			
		||||
			      struct xen_snd_front_shbuf *buf,
 | 
			
		||||
			      unsigned int buffer_sz)
 | 
			
		||||
{
 | 
			
		||||
	int num_pages_buffer, num_pages_dir, num_grefs;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	xen_snd_front_shbuf_clear(buf);
 | 
			
		||||
 | 
			
		||||
	num_pages_buffer = DIV_ROUND_UP(buffer_sz, XEN_PAGE_SIZE);
 | 
			
		||||
	/* number of pages the page directory consumes itself */
 | 
			
		||||
	num_pages_dir = DIV_ROUND_UP(num_pages_buffer,
 | 
			
		||||
				     XENSND_NUM_GREFS_PER_PAGE);
 | 
			
		||||
	num_grefs = num_pages_buffer + num_pages_dir;
 | 
			
		||||
 | 
			
		||||
	ret = alloc_int_buffers(buf, num_pages_dir,
 | 
			
		||||
				num_pages_buffer, num_grefs);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = grant_references(xb_dev, buf, num_pages_dir, num_pages_buffer,
 | 
			
		||||
			       num_grefs);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	fill_page_dir(buf, num_pages_dir);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,36 +0,0 @@
 | 
			
		|||
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Xen para-virtual sound device
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2016-2018 EPAM Systems Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __XEN_SND_FRONT_SHBUF_H
 | 
			
		||||
#define __XEN_SND_FRONT_SHBUF_H
 | 
			
		||||
 | 
			
		||||
#include <xen/grant_table.h>
 | 
			
		||||
 | 
			
		||||
#include "xen_snd_front_evtchnl.h"
 | 
			
		||||
 | 
			
		||||
struct xen_snd_front_shbuf {
 | 
			
		||||
	int num_grefs;
 | 
			
		||||
	grant_ref_t *grefs;
 | 
			
		||||
	u8 *directory;
 | 
			
		||||
	u8 *buffer;
 | 
			
		||||
	size_t buffer_sz;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
grant_ref_t xen_snd_front_shbuf_get_dir_start(struct xen_snd_front_shbuf *buf);
 | 
			
		||||
 | 
			
		||||
int xen_snd_front_shbuf_alloc(struct xenbus_device *xb_dev,
 | 
			
		||||
			      struct xen_snd_front_shbuf *buf,
 | 
			
		||||
			      unsigned int buffer_sz);
 | 
			
		||||
 | 
			
		||||
void xen_snd_front_shbuf_clear(struct xen_snd_front_shbuf *buf);
 | 
			
		||||
 | 
			
		||||
void xen_snd_front_shbuf_free(struct xen_snd_front_shbuf *buf);
 | 
			
		||||
 | 
			
		||||
#endif /* __XEN_SND_FRONT_SHBUF_H */
 | 
			
		||||
		Loading…
	
		Reference in a new issue