pinctrl: intel: Convert unsigned to unsigned int
[linux/fpc-iii.git] / sound / xen / xen_snd_front_shbuf.c
blob07ac176a41bab74d6f9b3b458067992230b30b3a
1 // SPDX-License-Identifier: GPL-2.0 OR MIT
3 /*
4 * Xen para-virtual sound device
6 * Copyright (C) 2016-2018 EPAM Systems Inc.
8 * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
9 */
11 #include <linux/kernel.h>
12 #include <xen/xen.h>
13 #include <xen/xenbus.h>
15 #include "xen_snd_front_shbuf.h"
17 grant_ref_t xen_snd_front_shbuf_get_dir_start(struct xen_snd_front_shbuf *buf)
19 if (!buf->grefs)
20 return GRANT_INVALID_REF;
22 return buf->grefs[0];
25 void xen_snd_front_shbuf_clear(struct xen_snd_front_shbuf *buf)
27 memset(buf, 0, sizeof(*buf));
30 void xen_snd_front_shbuf_free(struct xen_snd_front_shbuf *buf)
32 int i;
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);
41 kfree(buf->directory);
42 free_pages_exact(buf->buffer, buf->buffer_sz);
43 xen_snd_front_shbuf_clear(buf);
47 * number of grant references a page can hold with respect to the
48 * xensnd_page_directory header
50 #define XENSND_NUM_GREFS_PER_PAGE ((XEN_PAGE_SIZE - \
51 offsetof(struct xensnd_page_directory, gref)) / \
52 sizeof(grant_ref_t))
54 static void fill_page_dir(struct xen_snd_front_shbuf *buf,
55 int num_pages_dir)
57 struct xensnd_page_directory *page_dir;
58 unsigned char *ptr;
59 int i, cur_gref, grefs_left, to_copy;
61 ptr = buf->directory;
62 grefs_left = buf->num_grefs - num_pages_dir;
64 * skip grant references at the beginning, they are for pages granted
65 * for the page directory itself
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];
78 memcpy(&page_dir->gref, &buf->grefs[cur_gref],
79 to_copy * sizeof(grant_ref_t));
81 ptr += XEN_PAGE_SIZE;
82 grefs_left -= to_copy;
83 cur_gref += to_copy;
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)
92 grant_ref_t priv_gref_head;
93 unsigned long frame;
94 int ret, i, j, cur_ref;
95 int otherend_id;
97 ret = gnttab_alloc_grant_references(num_grefs, &priv_gref_head);
98 if (ret)
99 return ret;
101 buf->num_grefs = num_grefs;
102 otherend_id = xb_dev->otherend_id;
103 j = 0;
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;
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;
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;
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;
131 gnttab_free_grant_references(priv_gref_head);
132 fill_page_dir(buf, num_pages_dir);
133 return 0;
135 fail:
136 gnttab_free_grant_references(priv_gref_head);
137 return ret;
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)
144 buf->grefs = kcalloc(num_grefs, sizeof(*buf->grefs), GFP_KERNEL);
145 if (!buf->grefs)
146 return -ENOMEM;
148 buf->directory = kcalloc(num_pages_dir, XEN_PAGE_SIZE, GFP_KERNEL);
149 if (!buf->directory)
150 goto fail;
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;
157 return 0;
159 fail:
160 kfree(buf->grefs);
161 buf->grefs = NULL;
162 kfree(buf->directory);
163 buf->directory = NULL;
164 return -ENOMEM;
167 int xen_snd_front_shbuf_alloc(struct xenbus_device *xb_dev,
168 struct xen_snd_front_shbuf *buf,
169 unsigned int buffer_sz)
171 int num_pages_buffer, num_pages_dir, num_grefs;
172 int ret;
174 xen_snd_front_shbuf_clear(buf);
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;
182 ret = alloc_int_buffers(buf, num_pages_dir,
183 num_pages_buffer, num_grefs);
184 if (ret < 0)
185 return ret;
187 ret = grant_references(xb_dev, buf, num_pages_dir, num_pages_buffer,
188 num_grefs);
189 if (ret < 0)
190 return ret;
192 fill_page_dir(buf, num_pages_dir);
193 return 0;