diff options
author | Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> | 2018-11-30 02:42:05 -0500 |
---|---|---|
committer | Boris Ostrovsky <boris.ostrovsky@oracle.com> | 2018-12-18 12:19:37 -0500 |
commit | 58f9d806d16a38ed3bae11e2ada83393436a4956 (patch) | |
tree | 85823c492450b944b207f1004fee08462ba55d43 | |
parent | 5641f19bdfc4193f1c2d5a829896c25dd5c0ec3d (diff) |
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>
-rw-r--r-- | sound/xen/Kconfig | 1 | ||||
-rw-r--r-- | sound/xen/Makefile | 1 | ||||
-rw-r--r-- | sound/xen/xen_snd_front.c | 7 | ||||
-rw-r--r-- | sound/xen/xen_snd_front.h | 4 | ||||
-rw-r--r-- | sound/xen/xen_snd_front_alsa.c | 102 | ||||
-rw-r--r-- | sound/xen/xen_snd_front_shbuf.c | 194 | ||||
-rw-r--r-- | sound/xen/xen_snd_front_shbuf.h | 36 |
7 files changed, 84 insertions, 261 deletions
diff --git a/sound/xen/Kconfig b/sound/xen/Kconfig index 4f1fceea82d2..e4d7beb4df1c 100644 --- a/sound/xen/Kconfig +++ b/sound/xen/Kconfig | |||
@@ -5,6 +5,7 @@ config SND_XEN_FRONTEND | |||
5 | depends on XEN | 5 | depends on XEN |
6 | select SND_PCM | 6 | select SND_PCM |
7 | select XEN_XENBUS_FRONTEND | 7 | select XEN_XENBUS_FRONTEND |
8 | select XEN_FRONT_PGDIR_SHBUF | ||
8 | help | 9 | help |
9 | Choose this option if you want to enable a para-virtualized | 10 | Choose this option if you want to enable a para-virtualized |
10 | frontend sound driver for Xen guest OSes. | 11 | frontend sound driver for Xen guest OSes. |
diff --git a/sound/xen/Makefile b/sound/xen/Makefile index 1e6470ecc2f2..24031775b715 100644 --- a/sound/xen/Makefile +++ b/sound/xen/Makefile | |||
@@ -3,7 +3,6 @@ | |||
3 | snd_xen_front-objs := xen_snd_front.o \ | 3 | snd_xen_front-objs := xen_snd_front.o \ |
4 | xen_snd_front_cfg.o \ | 4 | xen_snd_front_cfg.o \ |
5 | xen_snd_front_evtchnl.o \ | 5 | xen_snd_front_evtchnl.o \ |
6 | xen_snd_front_shbuf.o \ | ||
7 | xen_snd_front_alsa.o | 6 | xen_snd_front_alsa.o |
8 | 7 | ||
9 | obj-$(CONFIG_SND_XEN_FRONTEND) += snd_xen_front.o | 8 | obj-$(CONFIG_SND_XEN_FRONTEND) += snd_xen_front.o |
diff --git a/sound/xen/xen_snd_front.c b/sound/xen/xen_snd_front.c index b089b13b5160..a9e5c2cd7698 100644 --- a/sound/xen/xen_snd_front.c +++ b/sound/xen/xen_snd_front.c | |||
@@ -16,12 +16,12 @@ | |||
16 | #include <xen/xen.h> | 16 | #include <xen/xen.h> |
17 | #include <xen/xenbus.h> | 17 | #include <xen/xenbus.h> |
18 | 18 | ||
19 | #include <xen/xen-front-pgdir-shbuf.h> | ||
19 | #include <xen/interface/io/sndif.h> | 20 | #include <xen/interface/io/sndif.h> |
20 | 21 | ||
21 | #include "xen_snd_front.h" | 22 | #include "xen_snd_front.h" |
22 | #include "xen_snd_front_alsa.h" | 23 | #include "xen_snd_front_alsa.h" |
23 | #include "xen_snd_front_evtchnl.h" | 24 | #include "xen_snd_front_evtchnl.h" |
24 | #include "xen_snd_front_shbuf.h" | ||
25 | 25 | ||
26 | static struct xensnd_req * | 26 | static struct xensnd_req * |
27 | be_stream_prepare_req(struct xen_snd_front_evtchnl *evtchnl, u8 operation) | 27 | 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, | |||
82 | } | 82 | } |
83 | 83 | ||
84 | int xen_snd_front_stream_prepare(struct xen_snd_front_evtchnl *evtchnl, | 84 | int xen_snd_front_stream_prepare(struct xen_snd_front_evtchnl *evtchnl, |
85 | struct xen_snd_front_shbuf *sh_buf, | 85 | struct xen_front_pgdir_shbuf *shbuf, |
86 | u8 format, unsigned int channels, | 86 | u8 format, unsigned int channels, |
87 | unsigned int rate, u32 buffer_sz, | 87 | unsigned int rate, u32 buffer_sz, |
88 | u32 period_sz) | 88 | u32 period_sz) |
@@ -99,7 +99,8 @@ int xen_snd_front_stream_prepare(struct xen_snd_front_evtchnl *evtchnl, | |||
99 | req->op.open.pcm_rate = rate; | 99 | req->op.open.pcm_rate = rate; |
100 | req->op.open.buffer_sz = buffer_sz; | 100 | req->op.open.buffer_sz = buffer_sz; |
101 | req->op.open.period_sz = period_sz; | 101 | req->op.open.period_sz = period_sz; |
102 | req->op.open.gref_directory = xen_snd_front_shbuf_get_dir_start(sh_buf); | 102 | req->op.open.gref_directory = |
103 | xen_front_pgdir_shbuf_get_dir_start(shbuf); | ||
103 | mutex_unlock(&evtchnl->ring_io_lock); | 104 | mutex_unlock(&evtchnl->ring_io_lock); |
104 | 105 | ||
105 | ret = be_stream_do_io(evtchnl); | 106 | ret = be_stream_do_io(evtchnl); |
diff --git a/sound/xen/xen_snd_front.h b/sound/xen/xen_snd_front.h index a2ea2463bcc5..05611f113b94 100644 --- a/sound/xen/xen_snd_front.h +++ b/sound/xen/xen_snd_front.h | |||
@@ -16,7 +16,7 @@ | |||
16 | struct xen_snd_front_card_info; | 16 | struct xen_snd_front_card_info; |
17 | struct xen_snd_front_evtchnl; | 17 | struct xen_snd_front_evtchnl; |
18 | struct xen_snd_front_evtchnl_pair; | 18 | struct xen_snd_front_evtchnl_pair; |
19 | struct xen_snd_front_shbuf; | 19 | struct xen_front_pgdir_shbuf; |
20 | struct xensnd_query_hw_param; | 20 | struct xensnd_query_hw_param; |
21 | 21 | ||
22 | struct xen_snd_front_info { | 22 | struct xen_snd_front_info { |
@@ -35,7 +35,7 @@ int xen_snd_front_stream_query_hw_param(struct xen_snd_front_evtchnl *evtchnl, | |||
35 | struct xensnd_query_hw_param *hw_param_resp); | 35 | struct xensnd_query_hw_param *hw_param_resp); |
36 | 36 | ||
37 | int xen_snd_front_stream_prepare(struct xen_snd_front_evtchnl *evtchnl, | 37 | int xen_snd_front_stream_prepare(struct xen_snd_front_evtchnl *evtchnl, |
38 | struct xen_snd_front_shbuf *sh_buf, | 38 | struct xen_front_pgdir_shbuf *shbuf, |
39 | u8 format, unsigned int channels, | 39 | u8 format, unsigned int channels, |
40 | unsigned int rate, u32 buffer_sz, | 40 | unsigned int rate, u32 buffer_sz, |
41 | u32 period_sz); | 41 | u32 period_sz); |
diff --git a/sound/xen/xen_snd_front_alsa.c b/sound/xen/xen_snd_front_alsa.c index 2cbd9679aca1..a7f413cb704d 100644 --- a/sound/xen/xen_snd_front_alsa.c +++ b/sound/xen/xen_snd_front_alsa.c | |||
@@ -15,17 +15,24 @@ | |||
15 | #include <sound/pcm_params.h> | 15 | #include <sound/pcm_params.h> |
16 | 16 | ||
17 | #include <xen/xenbus.h> | 17 | #include <xen/xenbus.h> |
18 | #include <xen/xen-front-pgdir-shbuf.h> | ||
18 | 19 | ||
19 | #include "xen_snd_front.h" | 20 | #include "xen_snd_front.h" |
20 | #include "xen_snd_front_alsa.h" | 21 | #include "xen_snd_front_alsa.h" |
21 | #include "xen_snd_front_cfg.h" | 22 | #include "xen_snd_front_cfg.h" |
22 | #include "xen_snd_front_evtchnl.h" | 23 | #include "xen_snd_front_evtchnl.h" |
23 | #include "xen_snd_front_shbuf.h" | ||
24 | 24 | ||
25 | struct xen_snd_front_pcm_stream_info { | 25 | struct xen_snd_front_pcm_stream_info { |
26 | struct xen_snd_front_info *front_info; | 26 | struct xen_snd_front_info *front_info; |
27 | struct xen_snd_front_evtchnl_pair *evt_pair; | 27 | struct xen_snd_front_evtchnl_pair *evt_pair; |
28 | struct xen_snd_front_shbuf sh_buf; | 28 | |
29 | /* This is the shared buffer with its backing storage. */ | ||
30 | struct xen_front_pgdir_shbuf shbuf; | ||
31 | u8 *buffer; | ||
32 | size_t buffer_sz; | ||
33 | int num_pages; | ||
34 | struct page **pages; | ||
35 | |||
29 | int index; | 36 | int index; |
30 | 37 | ||
31 | bool is_open; | 38 | bool is_open; |
@@ -214,12 +221,20 @@ static void stream_clear(struct xen_snd_front_pcm_stream_info *stream) | |||
214 | stream->out_frames = 0; | 221 | stream->out_frames = 0; |
215 | atomic_set(&stream->hw_ptr, 0); | 222 | atomic_set(&stream->hw_ptr, 0); |
216 | xen_snd_front_evtchnl_pair_clear(stream->evt_pair); | 223 | xen_snd_front_evtchnl_pair_clear(stream->evt_pair); |
217 | xen_snd_front_shbuf_clear(&stream->sh_buf); | 224 | memset(&stream->shbuf, 0, sizeof(stream->shbuf)); |
225 | stream->buffer = NULL; | ||
226 | stream->buffer_sz = 0; | ||
227 | stream->pages = NULL; | ||
228 | stream->num_pages = 0; | ||
218 | } | 229 | } |
219 | 230 | ||
220 | static void stream_free(struct xen_snd_front_pcm_stream_info *stream) | 231 | static void stream_free(struct xen_snd_front_pcm_stream_info *stream) |
221 | { | 232 | { |
222 | xen_snd_front_shbuf_free(&stream->sh_buf); | 233 | xen_front_pgdir_shbuf_unmap(&stream->shbuf); |
234 | xen_front_pgdir_shbuf_free(&stream->shbuf); | ||
235 | if (stream->buffer) | ||
236 | free_pages_exact(stream->buffer, stream->buffer_sz); | ||
237 | kfree(stream->pages); | ||
223 | stream_clear(stream); | 238 | stream_clear(stream); |
224 | } | 239 | } |
225 | 240 | ||
@@ -421,10 +436,34 @@ static int alsa_close(struct snd_pcm_substream *substream) | |||
421 | return 0; | 436 | return 0; |
422 | } | 437 | } |
423 | 438 | ||
439 | static int shbuf_setup_backstore(struct xen_snd_front_pcm_stream_info *stream, | ||
440 | size_t buffer_sz) | ||
441 | { | ||
442 | int i; | ||
443 | |||
444 | stream->buffer = alloc_pages_exact(stream->buffer_sz, GFP_KERNEL); | ||
445 | if (!stream->buffer) | ||
446 | return -ENOMEM; | ||
447 | |||
448 | stream->buffer_sz = buffer_sz; | ||
449 | stream->num_pages = DIV_ROUND_UP(stream->buffer_sz, PAGE_SIZE); | ||
450 | stream->pages = kcalloc(stream->num_pages, sizeof(struct page *), | ||
451 | GFP_KERNEL); | ||
452 | if (!stream->pages) | ||
453 | return -ENOMEM; | ||
454 | |||
455 | for (i = 0; i < stream->num_pages; i++) | ||
456 | stream->pages[i] = virt_to_page(stream->buffer + i * PAGE_SIZE); | ||
457 | |||
458 | return 0; | ||
459 | } | ||
460 | |||
424 | static int alsa_hw_params(struct snd_pcm_substream *substream, | 461 | static int alsa_hw_params(struct snd_pcm_substream *substream, |
425 | struct snd_pcm_hw_params *params) | 462 | struct snd_pcm_hw_params *params) |
426 | { | 463 | { |
427 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | 464 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); |
465 | struct xen_snd_front_info *front_info = stream->front_info; | ||
466 | struct xen_front_pgdir_shbuf_cfg buf_cfg; | ||
428 | int ret; | 467 | int ret; |
429 | 468 | ||
430 | /* | 469 | /* |
@@ -432,19 +471,32 @@ static int alsa_hw_params(struct snd_pcm_substream *substream, | |||
432 | * so free the previously allocated shared buffer if any. | 471 | * so free the previously allocated shared buffer if any. |
433 | */ | 472 | */ |
434 | stream_free(stream); | 473 | stream_free(stream); |
474 | ret = shbuf_setup_backstore(stream, params_buffer_bytes(params)); | ||
475 | if (ret < 0) | ||
476 | goto fail; | ||
435 | 477 | ||
436 | ret = xen_snd_front_shbuf_alloc(stream->front_info->xb_dev, | 478 | memset(&buf_cfg, 0, sizeof(buf_cfg)); |
437 | &stream->sh_buf, | 479 | buf_cfg.xb_dev = front_info->xb_dev; |
438 | params_buffer_bytes(params)); | 480 | buf_cfg.pgdir = &stream->shbuf; |
439 | if (ret < 0) { | 481 | buf_cfg.num_pages = stream->num_pages; |
440 | stream_free(stream); | 482 | buf_cfg.pages = stream->pages; |
441 | dev_err(&stream->front_info->xb_dev->dev, | 483 | |
442 | "Failed to allocate buffers for stream with index %d\n", | 484 | ret = xen_front_pgdir_shbuf_alloc(&buf_cfg); |
443 | stream->index); | 485 | if (ret < 0) |
444 | return ret; | 486 | goto fail; |
445 | } | 487 | |
488 | ret = xen_front_pgdir_shbuf_map(&stream->shbuf); | ||
489 | if (ret < 0) | ||
490 | goto fail; | ||
446 | 491 | ||
447 | return 0; | 492 | return 0; |
493 | |||
494 | fail: | ||
495 | stream_free(stream); | ||
496 | dev_err(&front_info->xb_dev->dev, | ||
497 | "Failed to allocate buffers for stream with index %d\n", | ||
498 | stream->index); | ||
499 | return ret; | ||
448 | } | 500 | } |
449 | 501 | ||
450 | static int alsa_hw_free(struct snd_pcm_substream *substream) | 502 | static int alsa_hw_free(struct snd_pcm_substream *substream) |
@@ -476,7 +528,7 @@ static int alsa_prepare(struct snd_pcm_substream *substream) | |||
476 | sndif_format = ret; | 528 | sndif_format = ret; |
477 | 529 | ||
478 | ret = xen_snd_front_stream_prepare(&stream->evt_pair->req, | 530 | ret = xen_snd_front_stream_prepare(&stream->evt_pair->req, |
479 | &stream->sh_buf, | 531 | &stream->shbuf, |
480 | sndif_format, | 532 | sndif_format, |
481 | runtime->channels, | 533 | runtime->channels, |
482 | runtime->rate, | 534 | runtime->rate, |
@@ -556,10 +608,10 @@ static int alsa_pb_copy_user(struct snd_pcm_substream *substream, | |||
556 | { | 608 | { |
557 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | 609 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); |
558 | 610 | ||
559 | if (unlikely(pos + count > stream->sh_buf.buffer_sz)) | 611 | if (unlikely(pos + count > stream->buffer_sz)) |
560 | return -EINVAL; | 612 | return -EINVAL; |
561 | 613 | ||
562 | if (copy_from_user(stream->sh_buf.buffer + pos, src, count)) | 614 | if (copy_from_user(stream->buffer + pos, src, count)) |
563 | return -EFAULT; | 615 | return -EFAULT; |
564 | 616 | ||
565 | return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); | 617 | 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, | |||
571 | { | 623 | { |
572 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | 624 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); |
573 | 625 | ||
574 | if (unlikely(pos + count > stream->sh_buf.buffer_sz)) | 626 | if (unlikely(pos + count > stream->buffer_sz)) |
575 | return -EINVAL; | 627 | return -EINVAL; |
576 | 628 | ||
577 | memcpy(stream->sh_buf.buffer + pos, src, count); | 629 | memcpy(stream->buffer + pos, src, count); |
578 | 630 | ||
579 | return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); | 631 | return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); |
580 | } | 632 | } |
@@ -586,14 +638,14 @@ static int alsa_cap_copy_user(struct snd_pcm_substream *substream, | |||
586 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | 638 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); |
587 | int ret; | 639 | int ret; |
588 | 640 | ||
589 | if (unlikely(pos + count > stream->sh_buf.buffer_sz)) | 641 | if (unlikely(pos + count > stream->buffer_sz)) |
590 | return -EINVAL; | 642 | return -EINVAL; |
591 | 643 | ||
592 | ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count); | 644 | ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count); |
593 | if (ret < 0) | 645 | if (ret < 0) |
594 | return ret; | 646 | return ret; |
595 | 647 | ||
596 | return copy_to_user(dst, stream->sh_buf.buffer + pos, count) ? | 648 | return copy_to_user(dst, stream->buffer + pos, count) ? |
597 | -EFAULT : 0; | 649 | -EFAULT : 0; |
598 | } | 650 | } |
599 | 651 | ||
@@ -604,14 +656,14 @@ static int alsa_cap_copy_kernel(struct snd_pcm_substream *substream, | |||
604 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | 656 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); |
605 | int ret; | 657 | int ret; |
606 | 658 | ||
607 | if (unlikely(pos + count > stream->sh_buf.buffer_sz)) | 659 | if (unlikely(pos + count > stream->buffer_sz)) |
608 | return -EINVAL; | 660 | return -EINVAL; |
609 | 661 | ||
610 | ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count); | 662 | ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count); |
611 | if (ret < 0) | 663 | if (ret < 0) |
612 | return ret; | 664 | return ret; |
613 | 665 | ||
614 | memcpy(dst, stream->sh_buf.buffer + pos, count); | 666 | memcpy(dst, stream->buffer + pos, count); |
615 | 667 | ||
616 | return 0; | 668 | return 0; |
617 | } | 669 | } |
@@ -622,10 +674,10 @@ static int alsa_pb_fill_silence(struct snd_pcm_substream *substream, | |||
622 | { | 674 | { |
623 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | 675 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); |
624 | 676 | ||
625 | if (unlikely(pos + count > stream->sh_buf.buffer_sz)) | 677 | if (unlikely(pos + count > stream->buffer_sz)) |
626 | return -EINVAL; | 678 | return -EINVAL; |
627 | 679 | ||
628 | memset(stream->sh_buf.buffer + pos, 0, count); | 680 | memset(stream->buffer + pos, 0, count); |
629 | 681 | ||
630 | return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); | 682 | return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); |
631 | } | 683 | } |
diff --git a/sound/xen/xen_snd_front_shbuf.c b/sound/xen/xen_snd_front_shbuf.c deleted file mode 100644 index 07ac176a41ba..000000000000 --- a/sound/xen/xen_snd_front_shbuf.c +++ /dev/null | |||
@@ -1,194 +0,0 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 OR MIT | ||
2 | |||
3 | /* | ||
4 | * Xen para-virtual sound device | ||
5 | * | ||
6 | * Copyright (C) 2016-2018 EPAM Systems Inc. | ||
7 | * | ||
8 | * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <xen/xen.h> | ||
13 | #include <xen/xenbus.h> | ||
14 | |||
15 | #include "xen_snd_front_shbuf.h" | ||
16 | |||
17 | grant_ref_t xen_snd_front_shbuf_get_dir_start(struct xen_snd_front_shbuf *buf) | ||
18 | { | ||
19 | if (!buf->grefs) | ||
20 | return GRANT_INVALID_REF; | ||
21 | |||
22 | return buf->grefs[0]; | ||
23 | } | ||
24 | |||
25 | void xen_snd_front_shbuf_clear(struct xen_snd_front_shbuf *buf) | ||
26 | { | ||
27 | memset(buf, 0, sizeof(*buf)); | ||
28 | } | ||
29 | |||
30 | void xen_snd_front_shbuf_free(struct xen_snd_front_shbuf *buf) | ||
31 | { | ||
32 | int i; | ||
33 | |||
34 | if (buf->grefs) { | ||
35 | for (i = 0; i < buf->num_grefs; i++) | ||
36 | if (buf->grefs[i] != GRANT_INVALID_REF) | ||
37 | gnttab_end_foreign_access(buf->grefs[i], | ||
38 | 0, 0UL); | ||
39 | kfree(buf->grefs); | ||
40 | } | ||
41 | kfree(buf->directory); | ||
42 | free_pages_exact(buf->buffer, buf->buffer_sz); | ||
43 | xen_snd_front_shbuf_clear(buf); | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * number of grant references a page can hold with respect to the | ||
48 | * xensnd_page_directory header | ||
49 | */ | ||
50 | #define XENSND_NUM_GREFS_PER_PAGE ((XEN_PAGE_SIZE - \ | ||
51 | offsetof(struct xensnd_page_directory, gref)) / \ | ||
52 | sizeof(grant_ref_t)) | ||
53 | |||
54 | static void fill_page_dir(struct xen_snd_front_shbuf *buf, | ||
55 | int num_pages_dir) | ||
56 | { | ||
57 | struct xensnd_page_directory *page_dir; | ||
58 | unsigned char *ptr; | ||
59 | int i, cur_gref, grefs_left, to_copy; | ||
60 | |||
61 | ptr = buf->directory; | ||
62 | grefs_left = buf->num_grefs - num_pages_dir; | ||
63 | /* | ||
64 | * skip grant references at the beginning, they are for pages granted | ||
65 | * for the page directory itself | ||
66 | */ | ||
67 | cur_gref = num_pages_dir; | ||
68 | for (i = 0; i < num_pages_dir; i++) { | ||
69 | page_dir = (struct xensnd_page_directory *)ptr; | ||
70 | if (grefs_left <= XENSND_NUM_GREFS_PER_PAGE) { | ||
71 | to_copy = grefs_left; | ||
72 | page_dir->gref_dir_next_page = GRANT_INVALID_REF; | ||
73 | } else { | ||
74 | to_copy = XENSND_NUM_GREFS_PER_PAGE; | ||
75 | page_dir->gref_dir_next_page = buf->grefs[i + 1]; | ||
76 | } | ||
77 | |||
78 | memcpy(&page_dir->gref, &buf->grefs[cur_gref], | ||
79 | to_copy * sizeof(grant_ref_t)); | ||
80 | |||
81 | ptr += XEN_PAGE_SIZE; | ||
82 | grefs_left -= to_copy; | ||
83 | cur_gref += to_copy; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | static int grant_references(struct xenbus_device *xb_dev, | ||
88 | struct xen_snd_front_shbuf *buf, | ||
89 | int num_pages_dir, int num_pages_buffer, | ||
90 | int num_grefs) | ||
91 | { | ||
92 | grant_ref_t priv_gref_head; | ||
93 | unsigned long frame; | ||
94 | int ret, i, j, cur_ref; | ||
95 | int otherend_id; | ||
96 | |||
97 | ret = gnttab_alloc_grant_references(num_grefs, &priv_gref_head); | ||
98 | if (ret) | ||
99 | return ret; | ||
100 | |||
101 | buf->num_grefs = num_grefs; | ||
102 | otherend_id = xb_dev->otherend_id; | ||
103 | j = 0; | ||
104 | |||
105 | for (i = 0; i < num_pages_dir; i++) { | ||
106 | cur_ref = gnttab_claim_grant_reference(&priv_gref_head); | ||
107 | if (cur_ref < 0) { | ||
108 | ret = cur_ref; | ||
109 | goto fail; | ||
110 | } | ||
111 | |||
112 | frame = xen_page_to_gfn(virt_to_page(buf->directory + | ||
113 | XEN_PAGE_SIZE * i)); | ||
114 | gnttab_grant_foreign_access_ref(cur_ref, otherend_id, frame, 0); | ||
115 | buf->grefs[j++] = cur_ref; | ||
116 | } | ||
117 | |||
118 | for (i = 0; i < num_pages_buffer; i++) { | ||
119 | cur_ref = gnttab_claim_grant_reference(&priv_gref_head); | ||
120 | if (cur_ref < 0) { | ||
121 | ret = cur_ref; | ||
122 | goto fail; | ||
123 | } | ||
124 | |||
125 | frame = xen_page_to_gfn(virt_to_page(buf->buffer + | ||
126 | XEN_PAGE_SIZE * i)); | ||
127 | gnttab_grant_foreign_access_ref(cur_ref, otherend_id, frame, 0); | ||
128 | buf->grefs[j++] = cur_ref; | ||
129 | } | ||
130 | |||
131 | gnttab_free_grant_references(priv_gref_head); | ||
132 | fill_page_dir(buf, num_pages_dir); | ||
133 | return 0; | ||
134 | |||
135 | fail: | ||
136 | gnttab_free_grant_references(priv_gref_head); | ||
137 | return ret; | ||
138 | } | ||
139 | |||
140 | static int alloc_int_buffers(struct xen_snd_front_shbuf *buf, | ||
141 | int num_pages_dir, int num_pages_buffer, | ||
142 | int num_grefs) | ||
143 | { | ||
144 | buf->grefs = kcalloc(num_grefs, sizeof(*buf->grefs), GFP_KERNEL); | ||
145 | if (!buf->grefs) | ||
146 | return -ENOMEM; | ||
147 | |||
148 | buf->directory = kcalloc(num_pages_dir, XEN_PAGE_SIZE, GFP_KERNEL); | ||
149 | if (!buf->directory) | ||
150 | goto fail; | ||
151 | |||
152 | buf->buffer_sz = num_pages_buffer * XEN_PAGE_SIZE; | ||
153 | buf->buffer = alloc_pages_exact(buf->buffer_sz, GFP_KERNEL); | ||
154 | if (!buf->buffer) | ||
155 | goto fail; | ||
156 | |||
157 | return 0; | ||
158 | |||
159 | fail: | ||
160 | kfree(buf->grefs); | ||
161 | buf->grefs = NULL; | ||
162 | kfree(buf->directory); | ||
163 | buf->directory = NULL; | ||
164 | return -ENOMEM; | ||
165 | } | ||
166 | |||
167 | int xen_snd_front_shbuf_alloc(struct xenbus_device *xb_dev, | ||
168 | struct xen_snd_front_shbuf *buf, | ||
169 | unsigned int buffer_sz) | ||
170 | { | ||
171 | int num_pages_buffer, num_pages_dir, num_grefs; | ||
172 | int ret; | ||
173 | |||
174 | xen_snd_front_shbuf_clear(buf); | ||
175 | |||
176 | num_pages_buffer = DIV_ROUND_UP(buffer_sz, XEN_PAGE_SIZE); | ||
177 | /* number of pages the page directory consumes itself */ | ||
178 | num_pages_dir = DIV_ROUND_UP(num_pages_buffer, | ||
179 | XENSND_NUM_GREFS_PER_PAGE); | ||
180 | num_grefs = num_pages_buffer + num_pages_dir; | ||
181 | |||
182 | ret = alloc_int_buffers(buf, num_pages_dir, | ||
183 | num_pages_buffer, num_grefs); | ||
184 | if (ret < 0) | ||
185 | return ret; | ||
186 | |||
187 | ret = grant_references(xb_dev, buf, num_pages_dir, num_pages_buffer, | ||
188 | num_grefs); | ||
189 | if (ret < 0) | ||
190 | return ret; | ||
191 | |||
192 | fill_page_dir(buf, num_pages_dir); | ||
193 | return 0; | ||
194 | } | ||
diff --git a/sound/xen/xen_snd_front_shbuf.h b/sound/xen/xen_snd_front_shbuf.h deleted file mode 100644 index d28e97c47b2c..000000000000 --- a/sound/xen/xen_snd_front_shbuf.h +++ /dev/null | |||
@@ -1,36 +0,0 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 OR MIT */ | ||
2 | |||
3 | /* | ||
4 | * Xen para-virtual sound device | ||
5 | * | ||
6 | * Copyright (C) 2016-2018 EPAM Systems Inc. | ||
7 | * | ||
8 | * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> | ||
9 | */ | ||
10 | |||
11 | #ifndef __XEN_SND_FRONT_SHBUF_H | ||
12 | #define __XEN_SND_FRONT_SHBUF_H | ||
13 | |||
14 | #include <xen/grant_table.h> | ||
15 | |||
16 | #include "xen_snd_front_evtchnl.h" | ||
17 | |||
18 | struct xen_snd_front_shbuf { | ||
19 | int num_grefs; | ||
20 | grant_ref_t *grefs; | ||
21 | u8 *directory; | ||
22 | u8 *buffer; | ||
23 | size_t buffer_sz; | ||
24 | }; | ||
25 | |||
26 | grant_ref_t xen_snd_front_shbuf_get_dir_start(struct xen_snd_front_shbuf *buf); | ||
27 | |||
28 | int xen_snd_front_shbuf_alloc(struct xenbus_device *xb_dev, | ||
29 | struct xen_snd_front_shbuf *buf, | ||
30 | unsigned int buffer_sz); | ||
31 | |||
32 | void xen_snd_front_shbuf_clear(struct xen_snd_front_shbuf *buf); | ||
33 | |||
34 | void xen_snd_front_shbuf_free(struct xen_snd_front_shbuf *buf); | ||
35 | |||
36 | #endif /* __XEN_SND_FRONT_SHBUF_H */ | ||