ixgbe: fix release queue mbufs
[dpdk.git] / drivers / net / xenvirt / rte_xen_lib.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 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
54 #include "rte_xen_lib.h"
55
56 /*
57  * The grant node format in xenstore for vring/mpool is:
58  * 0_rx_vring_gref = "gref1#, gref2#, gref3#"
59  * 0_mempool_gref  = "gref1#, gref2#, gref3#"
60  * each gref# is a grant reference for a shared page.
61  * In each shared page, we store the grant_node_item items.
62  */
63 struct grant_node_item {
64         uint32_t gref;
65         uint32_t pfn;
66 } __attribute__((packed));
67
68 /* fd for xen_gntalloc driver, used to allocate grant pages*/
69 int gntalloc_fd = -1;
70
71 /* xenstore path for local domain, now it is '/local/domain/domid/' */
72 static char *dompath = NULL;
73 /* handle to xenstore read/write operations */
74 static struct xs_handle *xs = NULL;
75
76 /*
77  * Reserve a virtual address space.
78  * On success, returns the pointer. On failure, returns NULL.
79  */
80 void *
81 get_xen_virtual(size_t size, size_t page_sz)
82 {
83         void *addr;
84         uintptr_t aligned_addr;
85
86         addr = mmap(NULL, size + page_sz, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
87         if (addr == MAP_FAILED) {
88                 RTE_LOG(ERR, PMD, "failed get a virtual area\n");
89                 return NULL;
90         }
91
92         aligned_addr = RTE_ALIGN_CEIL((uintptr_t)addr, page_sz);
93         addr = (void *)(aligned_addr);
94
95         return addr;
96 }
97
98 /*
99  * Get the physical address for virtual memory starting at va.
100  */
101 int
102 get_phys_map(void *va, phys_addr_t pa[], uint32_t pg_num, uint32_t pg_sz)
103 {
104         int32_t fd, rc = 0;
105         uint32_t i, nb;
106         off_t ofs;
107
108         ofs = (uintptr_t)va / pg_sz * sizeof(*pa);
109         nb = pg_num * sizeof(*pa);
110
111         if ((fd = open(PAGEMAP_FNAME, O_RDONLY)) < 0 ||
112                         (rc = pread(fd, pa, nb, ofs)) < 0 ||
113                         (rc -= nb) != 0) {
114                 RTE_LOG(ERR, PMD, "%s: failed read of %u bytes from \'%s\' "
115                         "at offset %zu, error code: %d\n",
116                         __func__, nb, PAGEMAP_FNAME, ofs, errno);
117                 rc = ENOENT;
118         }
119
120         close(fd);
121         for (i = 0; i != pg_num; i++)
122                 pa[i] = (pa[i] & PAGEMAP_PFN_MASK) * pg_sz;
123
124         return rc;
125 }
126
127 int
128 gntalloc_open(void)
129 {
130         gntalloc_fd = open(XEN_GNTALLOC_FNAME, O_RDWR);
131         return (gntalloc_fd != -1) ? 0 : -1;
132 }
133
134 void
135 gntalloc_close(void)
136 {
137         if (gntalloc_fd != -1)
138                 close(gntalloc_fd);
139         gntalloc_fd = -1;
140 }
141
142 void *
143 gntalloc(size_t size, uint32_t *gref, uint64_t *start_index)
144 {
145         int page_size = getpagesize();
146         uint32_t i, pg_num;
147         void *va;
148         int rv;
149         struct ioctl_gntalloc_alloc_gref *arg;
150         struct ioctl_gntalloc_dealloc_gref arg_d;
151
152         if (size % page_size) {
153                 RTE_LOG(ERR, PMD, "%s: %zu isn't multiple of page size\n",
154                         __func__, size);
155                 return NULL;
156         }
157
158         pg_num = size / page_size;
159         arg = malloc(sizeof(*arg) + (pg_num - 1) * sizeof(uint32_t));
160         if (arg == NULL)
161                 return NULL;
162         arg->domid = DOM0_DOMID;
163         arg->flags = GNTALLOC_FLAG_WRITABLE;
164         arg->count = pg_num;
165
166         rv = ioctl(gntalloc_fd, IOCTL_GNTALLOC_ALLOC_GREF, arg);
167         if (rv) {
168                 RTE_LOG(ERR, PMD, "%s: ioctl error\n", __func__);
169                 free(arg);
170                 return NULL;
171         }
172
173         va = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, gntalloc_fd, arg->index);
174         if (va == MAP_FAILED) {
175                 RTE_LOG(ERR, PMD, "%s: mmap failed\n", __func__);
176                 arg_d.count = pg_num;
177                 arg_d.index = arg->index;
178                 ioctl(gntalloc_fd, IOCTL_GNTALLOC_DEALLOC_GREF, arg_d);
179                 free(arg);
180                 return NULL;
181         }
182
183         if (gref) {
184                 for (i = 0; i < pg_num; i++) {
185                         gref[i] = arg->gref_ids[i];
186                 }
187         }
188         if (start_index)
189                 *start_index = arg->index;
190
191         free(arg);
192
193         return va;
194 }
195
196 int
197 grefwatch_from_alloc(uint32_t *gref, void **pptr)
198 {
199         int rv;
200         void *ptr;
201         int pg_size = getpagesize();
202         struct ioctl_gntalloc_alloc_gref arg = {
203                 .domid = DOM0_DOMID,
204                 .flags = GNTALLOC_FLAG_WRITABLE,
205                 .count = 1
206         };
207         struct ioctl_gntalloc_dealloc_gref arg_d;
208         struct ioctl_gntalloc_unmap_notify notify = {
209                 .action = UNMAP_NOTIFY_CLEAR_BYTE
210         };
211
212         rv = ioctl(gntalloc_fd, IOCTL_GNTALLOC_ALLOC_GREF, &arg);
213         if (rv) {
214                 RTE_LOG(ERR, PMD, "%s: ioctl error\n", __func__);
215                 return -1;
216         }
217
218         ptr = (void *)mmap(NULL, pg_size, PROT_READ|PROT_WRITE, MAP_SHARED, gntalloc_fd, arg.index);
219         arg_d.index = arg.index;
220         arg_d.count = 1;
221         if (ptr == MAP_FAILED) {
222                 RTE_LOG(ERR, PMD, "%s: mmap failed\n", __func__);
223                 ioctl(gntalloc_fd, IOCTL_GNTALLOC_DEALLOC_GREF, &arg_d);
224                 return -1;
225         }
226         if (pptr)
227                 *pptr = ptr;
228         if (gref)
229                 *gref = arg.gref_ids[0];
230
231         notify.index = arg.index;
232         rv = ioctl(gntalloc_fd, IOCTL_GNTALLOC_SET_UNMAP_NOTIFY, &notify);
233         if (rv) {
234                 RTE_LOG(ERR, PMD, "%s: unmap notify failed\n", __func__);
235                 munmap(ptr, pg_size);
236                 ioctl(gntalloc_fd, IOCTL_GNTALLOC_DEALLOC_GREF, &arg_d);
237                 return -1;
238         }
239
240         return 0;
241 }
242
243 void
244 gntfree(void *va, size_t sz, uint64_t start_index)
245 {
246         struct ioctl_gntalloc_dealloc_gref arg_d;
247
248         if (va && sz) {
249                 munmap(va, sz);
250                 arg_d.count = sz / getpagesize();
251                 arg_d.index = start_index;
252                 ioctl(gntalloc_fd, IOCTL_GNTALLOC_DEALLOC_GREF, &arg_d);
253         }
254 }
255
256 static int
257 xenstore_cleanup(void)
258 {
259         char store_path[PATH_MAX] = {0};
260
261         if (snprintf(store_path, sizeof(store_path),
262                 "%s%s", dompath, DPDK_XENSTORE_NODE) == -1)
263                 return -1;
264
265         if (xs_rm(xs, XBT_NULL, store_path) == false) {
266                 RTE_LOG(ERR, PMD, "%s: failed cleanup node\n", __func__);
267                 return -1;
268         }
269
270         return 0;
271 }
272
273 int
274 xenstore_init(void)
275 {
276         unsigned int len, domid;
277         char *buf;
278         static int cleanup = 0;
279         char *end;
280
281         xs = xs_domain_open();
282         if (xs == NULL) {
283                 RTE_LOG(ERR, PMD,"%s: xs_domain_open failed\n", __func__);
284                 return -1;
285         }
286         buf = xs_read(xs, XBT_NULL, "domid", &len);
287         if (buf == NULL) {
288                 RTE_LOG(ERR, PMD, "%s: failed read domid\n", __func__);
289                 return -1;
290         }
291         errno = 0;
292         domid = strtoul(buf, &end, 0);
293         if (errno != 0 || end == NULL || end == buf ||  domid == 0)
294                 return -1;
295
296         RTE_LOG(INFO, PMD, "retrieved dom ID = %d\n", domid);
297
298         dompath = xs_get_domain_path(xs, domid);
299         if (dompath == NULL)
300                 return -1;
301
302         xs_transaction_start(xs); /* When to stop transaction */
303
304         if (cleanup == 0) {
305                 if (xenstore_cleanup())
306                         return -1;
307                 cleanup = 1;
308         }
309
310         return 0;
311 }
312
313 int
314 xenstore_write(const char *key_str, const char *val_str)
315 {
316         char grant_path[PATH_MAX];
317         int rv, len;
318
319         if (xs == NULL) {
320                 RTE_LOG(ERR, PMD, "%s: xenstore init failed\n", __func__);
321                 return -1;
322         }
323         rv = snprintf(grant_path, sizeof(grant_path), "%s%s", dompath, key_str);
324         if (rv == -1) {
325                 RTE_LOG(ERR, PMD, "%s: snprintf %s %s failed\n",
326                         __func__, dompath, key_str);
327                 return -1;
328         }
329         len = strnlen(val_str, PATH_MAX);
330
331         if (xs_write(xs, XBT_NULL, grant_path, val_str, len) == false) {
332                 RTE_LOG(ERR, PMD, "%s: xs_write failed\n", __func__);
333                 return -1;
334         }
335
336         return 0;
337 }
338
339 int
340 grant_node_create(uint32_t pg_num, uint32_t *gref_arr, phys_addr_t *pa_arr, char *val_str, size_t str_size)
341 {
342         uint64_t start_index;
343         int pg_size;
344         uint32_t pg_shift;
345         void *ptr = NULL;
346         uint32_t count, entries_per_pg;
347         uint32_t i, j = 0, k = 0;;
348         uint32_t *gref_tmp;
349         int first = 1;
350         char tmp_str[PATH_MAX] = {0};
351         int rv = -1;
352
353         pg_size = getpagesize();
354         if (rte_is_power_of_2(pg_size) == 0) {
355                 return -1;
356         }
357         pg_shift = rte_bsf32(pg_size);
358         if (pg_size % sizeof(struct grant_node_item)) {
359                 RTE_LOG(ERR, PMD, "pg_size isn't a multiple of grant node item\n");
360                 return -1;
361         }
362
363         entries_per_pg = pg_size / sizeof(struct grant_node_item);
364         count  = (pg_num +  entries_per_pg - 1 ) / entries_per_pg;
365         gref_tmp = malloc(count * sizeof(uint32_t));
366         if (gref_tmp == NULL)
367                 return -1;
368         ptr = gntalloc(pg_size * count, gref_tmp, &start_index);
369         if (ptr == NULL) {
370                 RTE_LOG(ERR, PMD, "%s: gntalloc error of %d pages\n", __func__, count);
371                 free(gref_tmp);
372                 return -1;
373         }
374
375         while (j < pg_num) {
376                 if (first) {
377                         rv = snprintf(val_str, str_size, "%u", gref_tmp[k]);
378                         first = 0;
379                 } else {
380                         snprintf(tmp_str, PATH_MAX, "%s", val_str);
381                         rv = snprintf(val_str, str_size, "%s,%u", tmp_str, gref_tmp[k]);
382                 }
383                 k++;
384                 if (rv == -1)
385                         break;
386
387                 for (i = 0; i < entries_per_pg && j < pg_num ; i++) {
388                         ((struct grant_node_item *)ptr)->gref = gref_arr[j];
389                         ((struct grant_node_item *)ptr)->pfn =  pa_arr[j] >> pg_shift;
390                         ptr = RTE_PTR_ADD(ptr, sizeof(struct grant_node_item));
391                         j++;
392                 }
393         }
394         if (rv == -1) {
395                 gntfree(ptr, pg_size * count, start_index);
396         } else
397                 rv = 0;
398         free(gref_tmp);
399         return rv;
400 }
401
402
403 int
404 grant_gntalloc_mbuf_pool(struct rte_mempool *mpool, uint32_t pg_num, uint32_t *gref_arr, phys_addr_t *pa_arr, int mempool_idx)
405 {
406         char key_str[PATH_MAX] = {0};
407         char val_str[PATH_MAX] = {0};
408
409         if (grant_node_create(pg_num, gref_arr, pa_arr, val_str, sizeof(val_str))) {
410                 return -1;
411         }
412
413         if (snprintf(key_str, sizeof(key_str),
414                 DPDK_XENSTORE_PATH"%d"MEMPOOL_XENSTORE_STR, mempool_idx) == -1)
415                 return -1;
416         if (xenstore_write(key_str, val_str) == -1)
417                 return -1;
418
419         if (snprintf(key_str, sizeof(key_str),
420                 DPDK_XENSTORE_PATH"%d"MEMPOOL_VA_XENSTORE_STR, mempool_idx) == -1)
421                 return -1;
422         if (snprintf(val_str, sizeof(val_str), "%"PRIxPTR, (uintptr_t)mpool->elt_va_start) == -1)
423                 return -1;
424         if (xenstore_write(key_str, val_str) == -1)
425                 return -1;
426
427         return 0;
428 }