net/sfc: implement EF10 native Tx datapath
[dpdk.git] / drivers / net / xenvirt / rte_xen_lib.c
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  */
64 struct 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*/
70 int gntalloc_fd = -1;
71
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;
78
79 /*
80  * Reserve a virtual address space.
81  * On success, returns the pointer. On failure, returns NULL.
82  */
83 void *
84 get_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  */
104 int
105 get_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
130 int
131 gntalloc_open(void)
132 {
133         gntalloc_fd = open(XEN_GNTALLOC_FNAME, O_RDWR);
134         return (gntalloc_fd != -1) ? 0 : -1;
135 }
136
137 void
138 gntalloc_close(void)
139 {
140         if (gntalloc_fd != -1)
141                 close(gntalloc_fd);
142         gntalloc_fd = -1;
143 }
144
145 void *
146 gntalloc(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
199 int
200 grefwatch_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
246 void
247 gntfree(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
259 static int
260 xenstore_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
276 int
277 xenstore_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
315 int
316 xenstore_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
331 int
332 xenstore_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
357 int
358 grant_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
421 int
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)
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 }