4 * Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 #include <sys/types.h>
42 #include <sys/ioctl.h>
43 #include <xen/xen-compat.h>
44 #if __XEN_LATEST_INTERFACE_VERSION__ < 0x00040200
49 #include <xen/sys/gntalloc.h>
51 #include <rte_common.h>
52 #include <rte_string_fns.h>
53 #include <rte_malloc.h>
55 #include "rte_xen_lib.h"
58 * The grant node format in xenstore for vring/mpool is:
59 * 0_rx_vring_gref = "gref1#, gref2#, gref3#"
60 * 0_mempool_gref = "gref1#, gref2#, gref3#"
61 * each gref# is a grant reference for a shared page.
62 * In each shared page, we store the grant_node_item items.
64 struct grant_node_item {
67 } __attribute__((packed));
69 /* fd for xen_gntalloc driver, used to allocate grant pages*/
72 /* xenstore path for local domain, now it is '/local/domain/domid/' */
73 static char *dompath = NULL;
74 /* handle to xenstore read/write operations */
75 static struct xs_handle *xs = NULL;
76 /* flag to indicate if xenstore cleanup is required */
77 static bool is_xenstore_cleaned_up;
80 * Reserve a virtual address space.
81 * On success, returns the pointer. On failure, returns NULL.
84 get_xen_virtual(size_t size, size_t page_sz)
87 uintptr_t aligned_addr;
89 addr = mmap(NULL, size + page_sz, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
90 if (addr == MAP_FAILED) {
91 RTE_LOG(ERR, PMD, "failed get a virtual area\n");
95 aligned_addr = RTE_ALIGN_CEIL((uintptr_t)addr, page_sz);
96 addr = (void *)(aligned_addr);
102 * Get the physical address for virtual memory starting at va.
105 get_phys_map(void *va, phys_addr_t pa[], uint32_t pg_num, uint32_t pg_sz)
111 ofs = (uintptr_t)va / pg_sz * sizeof(*pa);
112 nb = pg_num * sizeof(*pa);
114 if ((fd = open(PAGEMAP_FNAME, O_RDONLY)) < 0 ||
115 (rc = pread(fd, pa, nb, ofs)) < 0 ||
117 RTE_LOG(ERR, PMD, "%s: failed read of %u bytes from \'%s\' "
118 "at offset %lu, error code: %d\n",
119 __func__, nb, PAGEMAP_FNAME, (unsigned long)ofs, errno);
124 for (i = 0; i != pg_num; i++)
125 pa[i] = (pa[i] & PAGEMAP_PFN_MASK) * pg_sz;
133 gntalloc_fd = open(XEN_GNTALLOC_FNAME, O_RDWR);
134 return (gntalloc_fd != -1) ? 0 : -1;
140 if (gntalloc_fd != -1)
146 gntalloc(size_t size, uint32_t *gref, uint64_t *start_index)
148 int page_size = getpagesize();
152 struct ioctl_gntalloc_alloc_gref *arg;
153 struct ioctl_gntalloc_dealloc_gref arg_d;
155 if (size % page_size) {
156 RTE_LOG(ERR, PMD, "%s: %zu isn't multiple of page size\n",
161 pg_num = size / page_size;
162 arg = malloc(sizeof(*arg) + (pg_num - 1) * sizeof(uint32_t));
165 arg->domid = DOM0_DOMID;
166 arg->flags = GNTALLOC_FLAG_WRITABLE;
169 rv = ioctl(gntalloc_fd, IOCTL_GNTALLOC_ALLOC_GREF, arg);
171 RTE_LOG(ERR, PMD, "%s: ioctl error\n", __func__);
176 va = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, gntalloc_fd, arg->index);
177 if (va == MAP_FAILED) {
178 RTE_LOG(ERR, PMD, "%s: mmap failed\n", __func__);
179 arg_d.count = pg_num;
180 arg_d.index = arg->index;
181 ioctl(gntalloc_fd, IOCTL_GNTALLOC_DEALLOC_GREF, arg_d);
187 for (i = 0; i < pg_num; i++) {
188 gref[i] = arg->gref_ids[i];
192 *start_index = arg->index;
200 grefwatch_from_alloc(uint32_t *gref, void **pptr)
204 int pg_size = getpagesize();
205 struct ioctl_gntalloc_alloc_gref arg = {
207 .flags = GNTALLOC_FLAG_WRITABLE,
210 struct ioctl_gntalloc_dealloc_gref arg_d;
211 struct ioctl_gntalloc_unmap_notify notify = {
212 .action = UNMAP_NOTIFY_CLEAR_BYTE
215 rv = ioctl(gntalloc_fd, IOCTL_GNTALLOC_ALLOC_GREF, &arg);
217 RTE_LOG(ERR, PMD, "%s: ioctl error\n", __func__);
221 ptr = (void *)mmap(NULL, pg_size, PROT_READ|PROT_WRITE, MAP_SHARED, gntalloc_fd, arg.index);
222 arg_d.index = arg.index;
224 if (ptr == MAP_FAILED) {
225 RTE_LOG(ERR, PMD, "%s: mmap failed\n", __func__);
226 ioctl(gntalloc_fd, IOCTL_GNTALLOC_DEALLOC_GREF, &arg_d);
232 *gref = arg.gref_ids[0];
234 notify.index = arg.index;
235 rv = ioctl(gntalloc_fd, IOCTL_GNTALLOC_SET_UNMAP_NOTIFY, ¬ify);
237 RTE_LOG(ERR, PMD, "%s: unmap notify failed\n", __func__);
238 munmap(ptr, pg_size);
239 ioctl(gntalloc_fd, IOCTL_GNTALLOC_DEALLOC_GREF, &arg_d);
247 gntfree(void *va, size_t sz, uint64_t start_index)
249 struct ioctl_gntalloc_dealloc_gref arg_d;
253 arg_d.count = sz / getpagesize();
254 arg_d.index = start_index;
255 ioctl(gntalloc_fd, IOCTL_GNTALLOC_DEALLOC_GREF, &arg_d);
260 xenstore_cleanup(void)
262 char store_path[PATH_MAX] = {0};
264 if (snprintf(store_path, sizeof(store_path),
265 "%s%s", dompath, DPDK_XENSTORE_NODE) == -1)
268 if (xs_rm(xs, XBT_NULL, store_path) == false) {
269 RTE_LOG(ERR, PMD, "%s: failed cleanup node\n", __func__);
279 unsigned int len, domid;
283 xs = xs_domain_open();
285 RTE_LOG(ERR, PMD,"%s: xs_domain_open failed\n", __func__);
288 buf = xs_read(xs, XBT_NULL, "domid", &len);
290 RTE_LOG(ERR, PMD, "%s: failed read domid\n", __func__);
294 domid = strtoul(buf, &end, 0);
295 if (errno != 0 || end == NULL || end == buf || domid == 0)
298 RTE_LOG(INFO, PMD, "retrieved dom ID = %d\n", domid);
300 dompath = xs_get_domain_path(xs, domid);
304 xs_transaction_start(xs); /* When to stop transaction */
306 if (is_xenstore_cleaned_up == 0) {
307 if (xenstore_cleanup())
309 is_xenstore_cleaned_up = 1;
316 xenstore_uninit(void)
320 if (is_xenstore_cleaned_up == 0) {
321 if (xenstore_cleanup())
323 is_xenstore_cleaned_up = 1;
332 xenstore_write(const char *key_str, const char *val_str)
334 char grant_path[PATH_MAX];
338 RTE_LOG(ERR, PMD, "%s: xenstore init failed\n", __func__);
341 rv = snprintf(grant_path, sizeof(grant_path), "%s%s", dompath, key_str);
343 RTE_LOG(ERR, PMD, "%s: snprintf %s %s failed\n",
344 __func__, dompath, key_str);
347 len = strnlen(val_str, PATH_MAX);
349 if (xs_write(xs, XBT_NULL, grant_path, val_str, len) == false) {
350 RTE_LOG(ERR, PMD, "%s: xs_write failed\n", __func__);
358 grant_node_create(uint32_t pg_num, uint32_t *gref_arr, phys_addr_t *pa_arr, char *val_str, size_t str_size)
360 uint64_t start_index;
364 uint32_t count, entries_per_pg;
365 uint32_t i, j = 0, k = 0;
368 char tmp_str[PATH_MAX] = {0};
371 pg_size = getpagesize();
372 if (rte_is_power_of_2(pg_size) == 0) {
375 pg_shift = rte_bsf32(pg_size);
376 if (pg_size % sizeof(struct grant_node_item)) {
377 RTE_LOG(ERR, PMD, "pg_size isn't a multiple of grant node item\n");
381 entries_per_pg = pg_size / sizeof(struct grant_node_item);
382 count = (pg_num + entries_per_pg - 1 ) / entries_per_pg;
383 gref_tmp = malloc(count * sizeof(uint32_t));
384 if (gref_tmp == NULL)
386 ptr = gntalloc(pg_size * count, gref_tmp, &start_index);
388 RTE_LOG(ERR, PMD, "%s: gntalloc error of %d pages\n", __func__, count);
395 rv = snprintf(val_str, str_size, "%u", gref_tmp[k]);
398 snprintf(tmp_str, PATH_MAX, "%s", val_str);
399 rv = snprintf(val_str, str_size, "%s,%u", tmp_str, gref_tmp[k]);
405 for (i = 0; i < entries_per_pg && j < pg_num ; i++) {
406 ((struct grant_node_item *)ptr)->gref = gref_arr[j];
407 ((struct grant_node_item *)ptr)->pfn = pa_arr[j] >> pg_shift;
408 ptr = RTE_PTR_ADD(ptr, sizeof(struct grant_node_item));
413 gntfree(ptr, pg_size * count, start_index);
422 grant_gntalloc_mbuf_pool(struct rte_mempool *mpool, uint32_t pg_num, uint32_t *gref_arr, phys_addr_t *pa_arr, int mempool_idx)
424 char key_str[PATH_MAX] = {0};
425 char val_str[PATH_MAX] = {0};
426 void *mempool_obj_va;
428 if (grant_node_create(pg_num, gref_arr, pa_arr, val_str, sizeof(val_str))) {
432 if (snprintf(key_str, sizeof(key_str),
433 DPDK_XENSTORE_PATH"%d"MEMPOOL_XENSTORE_STR, mempool_idx) == -1)
435 if (xenstore_write(key_str, val_str) == -1)
438 if (snprintf(key_str, sizeof(key_str),
439 DPDK_XENSTORE_PATH"%d"MEMPOOL_VA_XENSTORE_STR, mempool_idx) == -1)
441 if (mpool->nb_mem_chunks != 1) {
443 "mempool with more than 1 chunk is not supported\n");
446 mempool_obj_va = STAILQ_FIRST(&mpool->mem_list)->addr;
447 if (snprintf(val_str, sizeof(val_str), "%"PRIxPTR,
448 (uintptr_t)mempool_obj_va) == -1)
450 if (xenstore_write(key_str, val_str) == -1)