]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/dpdk/drivers/net/xenvirt/rte_xen_lib.c
update download target update for octopus release
[ceph.git] / ceph / src / seastar / dpdk / drivers / net / xenvirt / rte_xen_lib.c
CommitLineData
7c673cae
FG
1/*-
2 * BSD LICENSE
3 *
4 * Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
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
16 * distribution.
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.
20 *
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.
32 */
33
34#include <stdint.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <unistd.h>
38#include <string.h>
39#include <sys/types.h>
40#include <fcntl.h>
41#include <sys/mman.h>
42#include <sys/ioctl.h>
43#include <xen/xen-compat.h>
44#if __XEN_LATEST_INTERFACE_VERSION__ < 0x00040200
45#include <xs.h>
46#else
47#include <xenstore.h>
48#endif
49#include <xen/sys/gntalloc.h>
50
51#include <rte_common.h>
52#include <rte_string_fns.h>
53#include <rte_malloc.h>
54
55#include "rte_xen_lib.h"
56
57/*
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.
63 */
64struct grant_node_item {
65 uint32_t gref;
66 uint32_t pfn;
67} __attribute__((packed));
68
69/* fd for xen_gntalloc driver, used to allocate grant pages*/
70int gntalloc_fd = -1;
71
72/* xenstore path for local domain, now it is '/local/domain/domid/' */
73static char *dompath = NULL;
74/* handle to xenstore read/write operations */
75static struct xs_handle *xs = NULL;
76/* flag to indicate if xenstore cleanup is required */
77static bool is_xenstore_cleaned_up;
78
79/*
80 * Reserve a virtual address space.
81 * On success, returns the pointer. On failure, returns NULL.
82 */
83void *
84get_xen_virtual(size_t size, size_t page_sz)
85{
86 void *addr;
87 uintptr_t aligned_addr;
88
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");
92 return NULL;
93 }
94
95 aligned_addr = RTE_ALIGN_CEIL((uintptr_t)addr, page_sz);
96 addr = (void *)(aligned_addr);
97
98 return addr;
99}
100
101/*
102 * Get the physical address for virtual memory starting at va.
103 */
104int
105get_phys_map(void *va, phys_addr_t pa[], uint32_t pg_num, uint32_t pg_sz)
106{
107 int32_t fd, rc = 0;
108 uint32_t i, nb;
109 off_t ofs;
110
111 ofs = (uintptr_t)va / pg_sz * sizeof(*pa);
112 nb = pg_num * sizeof(*pa);
113
114 if ((fd = open(PAGEMAP_FNAME, O_RDONLY)) < 0 ||
115 (rc = pread(fd, pa, nb, ofs)) < 0 ||
116 (rc -= nb) != 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);
120 rc = ENOENT;
121 }
122
123 close(fd);
124 for (i = 0; i != pg_num; i++)
125 pa[i] = (pa[i] & PAGEMAP_PFN_MASK) * pg_sz;
126
127 return rc;
128}
129
130int
131gntalloc_open(void)
132{
133 gntalloc_fd = open(XEN_GNTALLOC_FNAME, O_RDWR);
134 return (gntalloc_fd != -1) ? 0 : -1;
135}
136
137void
138gntalloc_close(void)
139{
140 if (gntalloc_fd != -1)
141 close(gntalloc_fd);
142 gntalloc_fd = -1;
143}
144
145void *
146gntalloc(size_t size, uint32_t *gref, uint64_t *start_index)
147{
148 int page_size = getpagesize();
149 uint32_t i, pg_num;
150 void *va;
151 int rv;
152 struct ioctl_gntalloc_alloc_gref *arg;
153 struct ioctl_gntalloc_dealloc_gref arg_d;
154
155 if (size % page_size) {
156 RTE_LOG(ERR, PMD, "%s: %zu isn't multiple of page size\n",
157 __func__, size);
158 return NULL;
159 }
160
161 pg_num = size / page_size;
162 arg = malloc(sizeof(*arg) + (pg_num - 1) * sizeof(uint32_t));
163 if (arg == NULL)
164 return NULL;
165 arg->domid = DOM0_DOMID;
166 arg->flags = GNTALLOC_FLAG_WRITABLE;
167 arg->count = pg_num;
168
169 rv = ioctl(gntalloc_fd, IOCTL_GNTALLOC_ALLOC_GREF, arg);
170 if (rv) {
171 RTE_LOG(ERR, PMD, "%s: ioctl error\n", __func__);
172 free(arg);
173 return NULL;
174 }
175
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);
182 free(arg);
183 return NULL;
184 }
185
186 if (gref) {
187 for (i = 0; i < pg_num; i++) {
188 gref[i] = arg->gref_ids[i];
189 }
190 }
191 if (start_index)
192 *start_index = arg->index;
193
194 free(arg);
195
196 return va;
197}
198
199int
200grefwatch_from_alloc(uint32_t *gref, void **pptr)
201{
202 int rv;
203 void *ptr;
204 int pg_size = getpagesize();
205 struct ioctl_gntalloc_alloc_gref arg = {
206 .domid = DOM0_DOMID,
207 .flags = GNTALLOC_FLAG_WRITABLE,
208 .count = 1
209 };
210 struct ioctl_gntalloc_dealloc_gref arg_d;
211 struct ioctl_gntalloc_unmap_notify notify = {
212 .action = UNMAP_NOTIFY_CLEAR_BYTE
213 };
214
215 rv = ioctl(gntalloc_fd, IOCTL_GNTALLOC_ALLOC_GREF, &arg);
216 if (rv) {
217 RTE_LOG(ERR, PMD, "%s: ioctl error\n", __func__);
218 return -1;
219 }
220
221 ptr = (void *)mmap(NULL, pg_size, PROT_READ|PROT_WRITE, MAP_SHARED, gntalloc_fd, arg.index);
222 arg_d.index = arg.index;
223 arg_d.count = 1;
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);
227 return -1;
228 }
229 if (pptr)
230 *pptr = ptr;
231 if (gref)
232 *gref = arg.gref_ids[0];
233
234 notify.index = arg.index;
235 rv = ioctl(gntalloc_fd, IOCTL_GNTALLOC_SET_UNMAP_NOTIFY, &notify);
236 if (rv) {
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);
240 return -1;
241 }
242
243 return 0;
244}
245
246void
247gntfree(void *va, size_t sz, uint64_t start_index)
248{
249 struct ioctl_gntalloc_dealloc_gref arg_d;
250
251 if (va && sz) {
252 munmap(va, sz);
253 arg_d.count = sz / getpagesize();
254 arg_d.index = start_index;
255 ioctl(gntalloc_fd, IOCTL_GNTALLOC_DEALLOC_GREF, &arg_d);
256 }
257}
258
259static int
260xenstore_cleanup(void)
261{
262 char store_path[PATH_MAX] = {0};
263
264 if (snprintf(store_path, sizeof(store_path),
265 "%s%s", dompath, DPDK_XENSTORE_NODE) == -1)
266 return -1;
267
268 if (xs_rm(xs, XBT_NULL, store_path) == false) {
269 RTE_LOG(ERR, PMD, "%s: failed cleanup node\n", __func__);
270 return -1;
271 }
272
273 return 0;
274}
275
276int
277xenstore_init(void)
278{
279 unsigned int len, domid;
280 char *buf;
281 char *end;
282
283 xs = xs_domain_open();
284 if (xs == NULL) {
285 RTE_LOG(ERR, PMD,"%s: xs_domain_open failed\n", __func__);
286 return -1;
287 }
288 buf = xs_read(xs, XBT_NULL, "domid", &len);
289 if (buf == NULL) {
290 RTE_LOG(ERR, PMD, "%s: failed read domid\n", __func__);
291 return -1;
292 }
293 errno = 0;
294 domid = strtoul(buf, &end, 0);
295 if (errno != 0 || end == NULL || end == buf || domid == 0)
296 return -1;
297
298 RTE_LOG(INFO, PMD, "retrieved dom ID = %d\n", domid);
299
300 dompath = xs_get_domain_path(xs, domid);
301 if (dompath == NULL)
302 return -1;
303
304 xs_transaction_start(xs); /* When to stop transaction */
305
306 if (is_xenstore_cleaned_up == 0) {
307 if (xenstore_cleanup())
308 return -1;
309 is_xenstore_cleaned_up = 1;
310 }
311
312 return 0;
313}
314
315int
316xenstore_uninit(void)
317{
318 xs_close(xs);
319
320 if (is_xenstore_cleaned_up == 0) {
321 if (xenstore_cleanup())
322 return -1;
323 is_xenstore_cleaned_up = 1;
324 }
325 free(dompath);
326 dompath = NULL;
327
328 return 0;
329}
330
331int
332xenstore_write(const char *key_str, const char *val_str)
333{
334 char grant_path[PATH_MAX];
335 int rv, len;
336
337 if (xs == NULL) {
338 RTE_LOG(ERR, PMD, "%s: xenstore init failed\n", __func__);
339 return -1;
340 }
341 rv = snprintf(grant_path, sizeof(grant_path), "%s%s", dompath, key_str);
342 if (rv == -1) {
343 RTE_LOG(ERR, PMD, "%s: snprintf %s %s failed\n",
344 __func__, dompath, key_str);
345 return -1;
346 }
347 len = strnlen(val_str, PATH_MAX);
348
349 if (xs_write(xs, XBT_NULL, grant_path, val_str, len) == false) {
350 RTE_LOG(ERR, PMD, "%s: xs_write failed\n", __func__);
351 return -1;
352 }
353
354 return 0;
355}
356
357int
358grant_node_create(uint32_t pg_num, uint32_t *gref_arr, phys_addr_t *pa_arr, char *val_str, size_t str_size)
359{
360 uint64_t start_index;
361 int pg_size;
362 uint32_t pg_shift;
363 void *ptr = NULL;
364 uint32_t count, entries_per_pg;
365 uint32_t i, j = 0, k = 0;
366 uint32_t *gref_tmp;
367 int first = 1;
368 char tmp_str[PATH_MAX] = {0};
369 int rv = -1;
370
371 pg_size = getpagesize();
372 if (rte_is_power_of_2(pg_size) == 0) {
373 return -1;
374 }
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");
378 return -1;
379 }
380
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)
385 return -1;
386 ptr = gntalloc(pg_size * count, gref_tmp, &start_index);
387 if (ptr == NULL) {
388 RTE_LOG(ERR, PMD, "%s: gntalloc error of %d pages\n", __func__, count);
389 free(gref_tmp);
390 return -1;
391 }
392
393 while (j < pg_num) {
394 if (first) {
395 rv = snprintf(val_str, str_size, "%u", gref_tmp[k]);
396 first = 0;
397 } else {
398 snprintf(tmp_str, PATH_MAX, "%s", val_str);
399 rv = snprintf(val_str, str_size, "%s,%u", tmp_str, gref_tmp[k]);
400 }
401 k++;
402 if (rv == -1)
403 break;
404
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));
409 j++;
410 }
411 }
412 if (rv == -1) {
413 gntfree(ptr, pg_size * count, start_index);
414 } else
415 rv = 0;
416 free(gref_tmp);
417 return rv;
418}
419
420
421int
422grant_gntalloc_mbuf_pool(struct rte_mempool *mpool, uint32_t pg_num, uint32_t *gref_arr, phys_addr_t *pa_arr, int mempool_idx)
423{
424 char key_str[PATH_MAX] = {0};
425 char val_str[PATH_MAX] = {0};
426 void *mempool_obj_va;
427
428 if (grant_node_create(pg_num, gref_arr, pa_arr, val_str, sizeof(val_str))) {
429 return -1;
430 }
431
432 if (snprintf(key_str, sizeof(key_str),
433 DPDK_XENSTORE_PATH"%d"MEMPOOL_XENSTORE_STR, mempool_idx) == -1)
434 return -1;
435 if (xenstore_write(key_str, val_str) == -1)
436 return -1;
437
438 if (snprintf(key_str, sizeof(key_str),
439 DPDK_XENSTORE_PATH"%d"MEMPOOL_VA_XENSTORE_STR, mempool_idx) == -1)
440 return -1;
441 if (mpool->nb_mem_chunks != 1) {
442 RTE_LOG(ERR, PMD,
443 "mempool with more than 1 chunk is not supported\n");
444 return -1;
445 }
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)
449 return -1;
450 if (xenstore_write(key_str, val_str) == -1)
451 return -1;
452
453 return 0;
454}