Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2017 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "env_internal.h"
9 : : #include "pci_dpdk.h"
10 : :
11 : : #include <rte_config.h>
12 : : #include <rte_memory.h>
13 : : #include <rte_eal_memconfig.h>
14 : : #include <rte_dev.h>
15 : : #include <rte_pci.h>
16 : :
17 : : #include "spdk_internal/assert.h"
18 : :
19 : : #include "spdk/assert.h"
20 : : #include "spdk/likely.h"
21 : : #include "spdk/queue.h"
22 : : #include "spdk/util.h"
23 : : #include "spdk/memory.h"
24 : : #include "spdk/env_dpdk.h"
25 : : #include "spdk/log.h"
26 : :
27 : : #ifdef __linux__
28 : : #include <linux/version.h>
29 : : #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
30 : : #include <linux/vfio.h>
31 : : #include <rte_vfio.h>
32 : :
33 : : struct spdk_vfio_dma_map {
34 : : struct vfio_iommu_type1_dma_map map;
35 : : TAILQ_ENTRY(spdk_vfio_dma_map) tailq;
36 : : };
37 : :
38 : : struct vfio_cfg {
39 : : int fd;
40 : : bool enabled;
41 : : bool noiommu_enabled;
42 : : unsigned device_ref;
43 : : TAILQ_HEAD(, spdk_vfio_dma_map) maps;
44 : : pthread_mutex_t mutex;
45 : : };
46 : :
47 : : static struct vfio_cfg g_vfio = {
48 : : .fd = -1,
49 : : .enabled = false,
50 : : .noiommu_enabled = false,
51 : : .device_ref = 0,
52 : : .maps = TAILQ_HEAD_INITIALIZER(g_vfio.maps),
53 : : .mutex = PTHREAD_MUTEX_INITIALIZER
54 : : };
55 : : #endif
56 : : #endif
57 : :
58 : : #if DEBUG
59 : : #define DEBUG_PRINT(...) SPDK_ERRLOG(__VA_ARGS__)
60 : : #else
61 : : #define DEBUG_PRINT(...)
62 : : #endif
63 : :
64 : : struct map_page_cfg {
65 : : uint64_t shift;
66 : : uint64_t size;
67 : : uint64_t mask;
68 : : uint64_t num_pages_per_gb;
69 : : };
70 : :
71 : : /**
72 : : * g_map_page_cfg can not be static because it is used in the inline function
73 : : * spdk_mem_map_translate.
74 : : */
75 : : struct map_page_cfg g_map_page_cfg = {
76 : : .shift = SHIFT_2MB,
77 : : .size = VALUE_2MB,
78 : : .mask = MASK_2MB,
79 : : .num_pages_per_gb = 1UL << (SHIFT_1GB - SHIFT_2MB),
80 : : };
81 : :
82 : : #define MAP_PAGE_SHIFT (g_map_page_cfg.shift)
83 : : #define MAP_PAGE_SIZE (g_map_page_cfg.size)
84 : : #define MAP_PAGE_MASK (g_map_page_cfg.mask)
85 : : #define MAP_NUM_PAGES_PER_GB (g_map_page_cfg.num_pages_per_gb)
86 : :
87 : : #define MAP_256TB_IDX(vfn_page) ((vfn_page) >> (SHIFT_1GB - MAP_PAGE_SHIFT))
88 : : #define MAP_1GB_IDX(vfn_page) ((vfn_page) & ((1ULL << (SHIFT_1GB - MAP_PAGE_SHIFT)) - 1))
89 : : #define MAP_PAGE_OFFSET(ptr) (((uintptr_t)(ptr)) & MAP_PAGE_MASK)
90 : :
91 : : /* Page is registered */
92 : : #define REG_MAP_REGISTERED (1ULL << 62)
93 : :
94 : : /* A notification region barrier. The page translation entry that's marked
95 : : * with this flag must be unregistered separately. This allows contiguous
96 : : * regions to be unregistered in the same chunks they were registered.
97 : : */
98 : : #define REG_MAP_NOTIFY_START (1ULL << 63)
99 : :
100 : : /* Translation of a single page. */
101 : : struct map_page {
102 : : uint64_t translation;
103 : : };
104 : :
105 : : /* Second-level map table indexed by bits [page_shift..29] of the virtual address.
106 : : * Each entry contains the address translation or error for entries that haven't
107 : : * been retrieved yet.
108 : : */
109 : : struct map_1gb {
110 : : struct map_page map[0];
111 : : /**
112 : : * Page table space.
113 : : * Do not put any fields after this!
114 : : */
115 : : };
116 : :
117 : : #define MAP_SIZE_OF_MAP_1GB (sizeof(struct map_1gb) + MAP_NUM_PAGES_PER_GB * sizeof(struct map_page))
118 : :
119 : : /* Top-level map table indexed by bits [30..47] of the virtual address.
120 : : * Each entry points to a second-level map table or NULL.
121 : : */
122 : : struct map_256tb {
123 : : struct map_1gb *map[1ULL << (SHIFT_256TB - SHIFT_1GB)];
124 : : };
125 : :
126 : : /* Page-granularity memory address translation */
127 : : struct spdk_mem_map {
128 : : struct map_256tb map_256tb;
129 : : pthread_mutex_t mutex;
130 : : uint64_t default_translation;
131 : : struct spdk_mem_map_ops ops;
132 : : void *cb_ctx;
133 : : TAILQ_ENTRY(spdk_mem_map) tailq;
134 : : };
135 : :
136 : : /* Registrations map. The 64 bit translations are bit fields with the
137 : : * following layout (starting with the low bits):
138 : : * 0 - 61 : reserved
139 : : * 62 - 63 : flags
140 : : */
141 : : static struct spdk_mem_map *g_mem_reg_map;
142 : : static TAILQ_HEAD(spdk_mem_map_head, spdk_mem_map) g_spdk_mem_maps =
143 : : TAILQ_HEAD_INITIALIZER(g_spdk_mem_maps);
144 : : static pthread_mutex_t g_spdk_mem_map_mutex = PTHREAD_MUTEX_INITIALIZER;
145 : :
146 : : static bool g_legacy_mem;
147 : : static bool g_huge_pages = true;
148 : : static bool g_mem_event_cb_registered = false;
149 : :
150 : : /*
151 : : * Walk the currently registered memory via the main memory registration map
152 : : * and call the new map's notify callback for each virtually contiguous region.
153 : : */
154 : : static int
155 : 12166 : mem_map_notify_walk(struct spdk_mem_map *map, enum spdk_mem_map_notify_action action)
156 : : {
157 : : size_t idx_256tb;
158 : : uint64_t idx_1gb;
159 : 12166 : uint64_t contig_start = UINT64_MAX;
160 : 12166 : uint64_t contig_end = UINT64_MAX;
161 : : struct map_1gb *map_1gb;
162 : : int rc;
163 : :
164 [ - + ]: 12166 : if (!g_mem_reg_map) {
165 : 0 : return -EINVAL;
166 : : }
167 : :
168 : : /* Hold the memory registration map mutex so no new registrations can be added while we are looping. */
169 [ + + + - ]: 12166 : pthread_mutex_lock(&g_mem_reg_map->mutex);
170 : :
171 [ + + ]: 112209798 : for (idx_256tb = 0;
172 [ + + ]: 3178246022 : idx_256tb < sizeof(g_mem_reg_map->map_256tb.map) / sizeof(g_mem_reg_map->map_256tb.map[0]);
173 : 3178233856 : idx_256tb++) {
174 [ + - + - : 3178233898 : map_1gb = g_mem_reg_map->map_256tb.map[idx_256tb];
+ - + - ]
175 : :
176 [ + + ]: 3178233898 : if (!map_1gb) {
177 [ + + ]: 3178218921 : if (contig_start != UINT64_MAX) {
178 : : /* End of of a virtually contiguous range */
179 [ # # # # : 0 : rc = map->ops.notify_cb(map->cb_ctx, map, action,
# # # # #
# # # #
# ]
180 : 0 : (void *)contig_start,
181 [ # # ]: 0 : contig_end - contig_start + MAP_PAGE_SIZE);
182 : : /* Don't bother handling unregister failures. It can't be any worse */
183 [ # # # # ]: 0 : if (rc != 0 && action == SPDK_MEM_MAP_NOTIFY_REGISTER) {
184 : 0 : goto err_unregister;
185 : : }
186 : 0 : }
187 : 3178218921 : contig_start = UINT64_MAX;
188 : 3178218921 : continue;
189 : : }
190 : :
191 [ + + + + ]: 75187408 : for (idx_1gb = 0; idx_1gb < MAP_NUM_PAGES_PER_GB; idx_1gb++) {
192 [ + + + + : 75236627 : if ((map_1gb->map[idx_1gb].translation & REG_MAP_REGISTERED) &&
+ - + - +
- + + +
+ ]
193 [ + + ]: 7729770 : (contig_start == UINT64_MAX ||
194 [ + + + - : 7727732 : (map_1gb->map[idx_1gb].translation & REG_MAP_NOTIFY_START) == 0)) {
+ - + - +
- ]
195 : : /* Rebuild the virtual address from the indexes */
196 [ + + + - ]: 7742881 : uint64_t vaddr = (idx_256tb << SHIFT_1GB) | (idx_1gb << MAP_PAGE_SHIFT);
197 : :
198 [ + + ]: 7742881 : if (contig_start == UINT64_MAX) {
199 : 24319 : contig_start = vaddr;
200 : 2038 : }
201 : :
202 : 7742881 : contig_end = vaddr;
203 : 64588 : } else {
204 [ + + ]: 67429592 : if (contig_start != UINT64_MAX) {
205 : : /* End of of a virtually contiguous range */
206 [ + - + - : 45104 : rc = map->ops.notify_cb(map->cb_ctx, map, action,
+ - - + +
- + - +
- ]
207 : 2038 : (void *)contig_start,
208 [ + - ]: 24319 : contig_end - contig_start + MAP_PAGE_SIZE);
209 : : /* Don't bother handling unregister failures. It can't be any worse */
210 [ + + + + ]: 24319 : if (rc != 0 && action == SPDK_MEM_MAP_NOTIFY_REGISTER) {
211 : 42 : goto err_unregister;
212 : : }
213 : :
214 : : /* This page might be a part of a neighbour region, so process
215 : : * it again. The idx_1gb will be incremented immediately.
216 : : */
217 : 24277 : idx_1gb--;
218 : 2036 : }
219 : 67429550 : contig_start = UINT64_MAX;
220 : : }
221 : 2837510 : }
222 : 428 : }
223 : :
224 [ - + - + ]: 12124 : pthread_mutex_unlock(&g_mem_reg_map->mutex);
225 : 12124 : return 0;
226 : :
227 : 40 : err_unregister:
228 : : /* Unwind to the first empty translation so we don't unregister
229 : : * a region that just failed to register.
230 : : */
231 [ + + + + ]: 42 : idx_256tb = MAP_256TB_IDX((contig_start >> MAP_PAGE_SHIFT) - 1);
232 [ + + + + ]: 42 : idx_1gb = MAP_1GB_IDX((contig_start >> MAP_PAGE_SHIFT) - 1);
233 : 42 : contig_start = UINT64_MAX;
234 : 42 : contig_end = UINT64_MAX;
235 : :
236 : : /* Unregister any memory we managed to register before the failure */
237 [ + + ]: 84 : for (; idx_256tb < SIZE_MAX; idx_256tb--) {
238 [ + - + - : 42 : map_1gb = g_mem_reg_map->map_256tb.map[idx_256tb];
+ - + - ]
239 : :
240 [ + + ]: 42 : if (!map_1gb) {
241 [ # # ]: 0 : if (contig_end != UINT64_MAX) {
242 : : /* End of of a virtually contiguous range */
243 [ # # # # : 0 : map->ops.notify_cb(map->cb_ctx, map,
# # # # #
# # # #
# ]
244 : : SPDK_MEM_MAP_NOTIFY_UNREGISTER,
245 : 0 : (void *)contig_start,
246 [ # # ]: 0 : contig_end - contig_start + MAP_PAGE_SIZE);
247 : 0 : }
248 : 0 : contig_end = UINT64_MAX;
249 : 0 : continue;
250 : : }
251 : :
252 [ + + ]: 378 : for (; idx_1gb < UINT64_MAX; idx_1gb--) {
253 : : /* Rebuild the virtual address from the indexes */
254 [ + + + - ]: 336 : uint64_t vaddr = (idx_256tb << SHIFT_1GB) | (idx_1gb << MAP_PAGE_SHIFT);
255 [ + + + + : 336 : if ((map_1gb->map[idx_1gb].translation & REG_MAP_REGISTERED) &&
+ - + - +
- + + #
# ]
256 [ - + # # : 8 : (contig_end == UINT64_MAX || (map_1gb->map[idx_1gb].translation & REG_MAP_NOTIFY_START) == 0)) {
# # # # #
# # # ]
257 : :
258 [ + + ]: 168 : if (contig_end == UINT64_MAX) {
259 : 168 : contig_end = vaddr;
260 : 8 : }
261 : 168 : contig_start = vaddr;
262 : 8 : } else {
263 [ + + ]: 168 : if (contig_end != UINT64_MAX) {
264 [ + + + - : 126 : if (map_1gb->map[idx_1gb].translation & REG_MAP_NOTIFY_START) {
+ - + - +
- + - ]
265 : 0 : contig_start = vaddr;
266 : 0 : }
267 : : /* End of of a virtually contiguous range */
268 [ + - + - : 228 : map->ops.notify_cb(map->cb_ctx, map,
+ - - + +
- + - +
- ]
269 : : SPDK_MEM_MAP_NOTIFY_UNREGISTER,
270 : 6 : (void *)contig_start,
271 [ + - ]: 126 : contig_end - contig_start + MAP_PAGE_SIZE);
272 : 6 : }
273 : 168 : contig_end = UINT64_MAX;
274 : : }
275 : 16 : }
276 [ + - ]: 42 : idx_1gb = MAP_NUM_PAGES_PER_GB - 1;
277 : 2 : }
278 : :
279 [ + + + - ]: 42 : pthread_mutex_unlock(&g_mem_reg_map->mutex);
280 : 42 : return rc;
281 : 430 : }
282 : :
283 : : struct spdk_mem_map *
284 : 11751 : spdk_mem_map_alloc(uint64_t default_translation, const struct spdk_mem_map_ops *ops, void *cb_ctx)
285 : : {
286 : : struct spdk_mem_map *map;
287 : : int rc;
288 : : size_t i;
289 : :
290 : 11751 : map = calloc(1, sizeof(*map));
291 [ + + ]: 11751 : if (map == NULL) {
292 : 0 : return NULL;
293 : : }
294 : :
295 [ + + + + : 11751 : if (pthread_mutex_init(&map->mutex, NULL)) {
- + ]
296 : 0 : free(map);
297 : 0 : return NULL;
298 : : }
299 : :
300 [ + - + - ]: 11751 : map->default_translation = default_translation;
301 [ + - + - ]: 11751 : map->cb_ctx = cb_ctx;
302 [ + + ]: 11751 : if (ops) {
303 [ + - ]: 8957 : map->ops = *ops;
304 : 284 : }
305 : :
306 [ + + + + : 11751 : if (ops && ops->notify_cb) {
+ - + + ]
307 [ + + ]: 6247 : pthread_mutex_lock(&g_spdk_mem_map_mutex);
308 : 6247 : rc = mem_map_notify_walk(map, SPDK_MEM_MAP_NOTIFY_REGISTER);
309 [ + + ]: 6247 : if (rc != 0) {
310 [ + + ]: 42 : pthread_mutex_unlock(&g_spdk_mem_map_mutex);
311 : 42 : DEBUG_PRINT("Initial mem_map notify failed\n");
312 [ + + + - ]: 42 : pthread_mutex_destroy(&map->mutex);
313 [ + + ]: 11010090 : for (i = 0; i < sizeof(map->map_256tb.map) / sizeof(map->map_256tb.map[0]); i++) {
314 [ + - + - : 11010048 : free(map->map_256tb.map[i]);
+ - + - ]
315 : 524288 : }
316 : 42 : free(map);
317 : 42 : return NULL;
318 : : }
319 [ + - + - : 6205 : TAILQ_INSERT_TAIL(&g_spdk_mem_maps, map, tailq);
+ - + - +
- + - + -
+ - + - +
- + - +
- ]
320 [ + + ]: 6205 : pthread_mutex_unlock(&g_spdk_mem_map_mutex);
321 : 216 : }
322 : :
323 : 11709 : return map;
324 : 354 : }
325 : :
326 : : void
327 : 11481 : spdk_mem_map_free(struct spdk_mem_map **pmap)
328 : : {
329 : : struct spdk_mem_map *map;
330 : : size_t i;
331 : :
332 [ + + ]: 11481 : if (!pmap) {
333 : 0 : return;
334 : : }
335 : :
336 [ + - ]: 11481 : map = *pmap;
337 : :
338 [ + + ]: 11481 : if (!map) {
339 : 344 : return;
340 : : }
341 : :
342 [ + + + - : 11137 : if (map->ops.notify_cb) {
+ - + + ]
343 [ + + ]: 5919 : pthread_mutex_lock(&g_spdk_mem_map_mutex);
344 : 5919 : mem_map_notify_walk(map, SPDK_MEM_MAP_NOTIFY_UNREGISTER);
345 [ + + + - : 5919 : TAILQ_REMOVE(&g_spdk_mem_maps, map, tailq);
+ - - + #
# # # # #
# # # # #
# # # # #
# # - + -
+ - + - +
+ - + - +
- + - + -
+ - + - ]
346 [ + + ]: 5919 : pthread_mutex_unlock(&g_spdk_mem_map_mutex);
347 : 212 : }
348 : :
349 [ + + ]: 2919508865 : for (i = 0; i < sizeof(map->map_256tb.map) / sizeof(map->map_256tb.map[0]); i++) {
350 [ + - + - : 2919497728 : free(map->map_256tb.map[i]);
+ - + - ]
351 : 90177536 : }
352 : :
353 [ + + + - ]: 11137 : pthread_mutex_destroy(&map->mutex);
354 : :
355 : 11137 : free(map);
356 [ + - ]: 11137 : *pmap = NULL;
357 : 360 : }
358 : :
359 : : uint64_t
360 : 0 : spdk_mem_map_get_page_size(void)
361 : : {
362 [ # # ]: 0 : return g_map_page_cfg.size;
363 : : }
364 : :
365 : : int
366 : 39394 : spdk_mem_register(void *_vaddr, size_t len)
367 : : {
368 : : struct spdk_mem_map *map;
369 : : int rc;
370 : 39394 : uint64_t vaddr = (uintptr_t)_vaddr;
371 : : uint64_t seg_vaddr;
372 : : size_t seg_len;
373 : : uint64_t reg;
374 : :
375 [ + + - + ]: 39394 : if ((uintptr_t)vaddr & ~MASK_256TB) {
376 : 0 : DEBUG_PRINT("invalid usermode virtual address %jx\n", vaddr);
377 : 0 : return -EINVAL;
378 : : }
379 : :
380 [ + + + + : 39394 : if (((uintptr_t)vaddr & MAP_PAGE_MASK) || (len & MAP_PAGE_MASK)) {
+ - + + ]
381 : 84 : DEBUG_PRINT("invalid %s parameters, vaddr=%jx len=%ju\n",
382 : : __func__, vaddr, len);
383 : 84 : return -EINVAL;
384 : : }
385 : :
386 [ + + ]: 39310 : if (len == 0) {
387 : 0 : return 0;
388 : : }
389 : :
390 [ + + ]: 39310 : pthread_mutex_lock(&g_spdk_mem_map_mutex);
391 : :
392 : 39310 : seg_vaddr = vaddr;
393 : 39310 : seg_len = len;
394 [ + + ]: 3151572 : while (seg_len > 0) {
395 : 3112304 : reg = spdk_mem_map_translate(g_mem_reg_map, (uint64_t)seg_vaddr, NULL);
396 [ + + + + ]: 3112304 : if (reg & REG_MAP_REGISTERED) {
397 [ + + ]: 42 : pthread_mutex_unlock(&g_spdk_mem_map_mutex);
398 : 42 : return -EBUSY;
399 : : }
400 [ + - ]: 3112262 : seg_vaddr += MAP_PAGE_SIZE;
401 [ + - ]: 3112262 : seg_len -= MAP_PAGE_SIZE;
402 : : }
403 : :
404 : 39268 : seg_vaddr = vaddr;
405 : 39268 : seg_len = 0;
406 [ + + ]: 3151488 : while (len > 0) {
407 [ + + ]: 3130851 : spdk_mem_map_set_translation(g_mem_reg_map, (uint64_t)vaddr, MAP_PAGE_SIZE,
408 [ + - + - : 18631 : seg_len == 0 ? REG_MAP_REGISTERED | REG_MAP_NOTIFY_START : REG_MAP_REGISTERED);
+ - ]
409 [ + - ]: 3112220 : seg_len += MAP_PAGE_SIZE;
410 [ + - ]: 3112220 : vaddr += MAP_PAGE_SIZE;
411 [ + - ]: 3112220 : len -= MAP_PAGE_SIZE;
412 : : }
413 : :
414 [ + + + - : 112790 : TAILQ_FOREACH(map, &g_spdk_mem_maps, tailq) {
+ - + - ]
415 [ + - + - : 73524 : rc = map->ops.notify_cb(map->cb_ctx, map, SPDK_MEM_MAP_NOTIFY_REGISTER,
+ - - + +
- + - +
- ]
416 : 934 : (void *)seg_vaddr, seg_len);
417 [ + + ]: 73524 : if (rc != 0) {
418 [ # # ]: 2 : pthread_mutex_unlock(&g_spdk_mem_map_mutex);
419 : 2 : return rc;
420 : : }
421 : 934 : }
422 : :
423 [ + + ]: 39266 : pthread_mutex_unlock(&g_spdk_mem_map_mutex);
424 : 39266 : return 0;
425 : 563 : }
426 : :
427 : : int
428 : 34812 : spdk_mem_unregister(void *_vaddr, size_t len)
429 : : {
430 : : struct spdk_mem_map *map;
431 : : int rc;
432 : 34812 : uint64_t vaddr = (uintptr_t)_vaddr;
433 : : uint64_t seg_vaddr;
434 : : size_t seg_len;
435 : : uint64_t reg, newreg;
436 : :
437 [ + + - + ]: 34812 : if ((uintptr_t)vaddr & ~MASK_256TB) {
438 : 0 : DEBUG_PRINT("invalid usermode virtual address %jx\n", vaddr);
439 : 0 : return -EINVAL;
440 : : }
441 : :
442 [ + - + + : 34812 : if (((uintptr_t)vaddr & MAP_PAGE_MASK) || (len & MAP_PAGE_MASK)) {
+ - - + ]
443 : 0 : DEBUG_PRINT("invalid %s parameters, vaddr=%jx len=%ju\n",
444 : : __func__, vaddr, len);
445 : 0 : return -EINVAL;
446 : : }
447 : :
448 [ + + ]: 34812 : pthread_mutex_lock(&g_spdk_mem_map_mutex);
449 : :
450 : : /* The first page must be a start of a region. Also check if it's
451 : : * registered to make sure we don't return -ERANGE for non-registered
452 : : * regions.
453 : : */
454 : 34812 : reg = spdk_mem_map_translate(g_mem_reg_map, (uint64_t)vaddr, NULL);
455 [ + + + + : 34812 : if ((reg & REG_MAP_REGISTERED) && (reg & REG_MAP_NOTIFY_START) == 0) {
+ - + + ]
456 [ + + ]: 84 : pthread_mutex_unlock(&g_spdk_mem_map_mutex);
457 : 84 : return -ERANGE;
458 : : }
459 : :
460 : 34728 : seg_vaddr = vaddr;
461 : 34728 : seg_len = len;
462 [ + + ]: 677353 : while (seg_len > 0) {
463 : 642667 : reg = spdk_mem_map_translate(g_mem_reg_map, (uint64_t)seg_vaddr, NULL);
464 [ + + + + ]: 642667 : if ((reg & REG_MAP_REGISTERED) == 0) {
465 [ + + ]: 42 : pthread_mutex_unlock(&g_spdk_mem_map_mutex);
466 : 42 : return -EINVAL;
467 : : }
468 [ + - ]: 642625 : seg_vaddr += MAP_PAGE_SIZE;
469 [ + - ]: 642625 : seg_len -= MAP_PAGE_SIZE;
470 : : }
471 : :
472 : 34686 : newreg = spdk_mem_map_translate(g_mem_reg_map, (uint64_t)seg_vaddr, NULL);
473 : : /* If the next page is registered, it must be a start of a region as well,
474 : : * otherwise we'd be unregistering only a part of a region.
475 : : */
476 [ + + + + : 34686 : if ((newreg & REG_MAP_NOTIFY_START) == 0 && (newreg & REG_MAP_REGISTERED)) {
+ - + + ]
477 [ + + ]: 42 : pthread_mutex_unlock(&g_spdk_mem_map_mutex);
478 : 42 : return -ERANGE;
479 : : }
480 : 34644 : seg_vaddr = vaddr;
481 : 34644 : seg_len = 0;
482 : :
483 [ + + ]: 677227 : while (len > 0) {
484 : 642583 : reg = spdk_mem_map_translate(g_mem_reg_map, (uint64_t)vaddr, NULL);
485 [ + - ]: 642583 : spdk_mem_map_set_translation(g_mem_reg_map, (uint64_t)vaddr, MAP_PAGE_SIZE, 0);
486 : :
487 [ + + + + : 642583 : if (seg_len > 0 && (reg & REG_MAP_NOTIFY_START)) {
+ + ]
488 [ + + + - : 420 : TAILQ_FOREACH_REVERSE(map, &g_spdk_mem_maps, spdk_mem_map_head, tailq) {
+ - + - +
+ + - + -
+ - + - +
- + - ]
489 [ + - + - : 210 : rc = map->ops.notify_cb(map->cb_ctx, map, SPDK_MEM_MAP_NOTIFY_UNREGISTER,
+ - - + +
- + - +
- ]
490 : 10 : (void *)seg_vaddr, seg_len);
491 [ + + ]: 210 : if (rc != 0) {
492 [ # # ]: 0 : pthread_mutex_unlock(&g_spdk_mem_map_mutex);
493 : 0 : return rc;
494 : : }
495 : 10 : }
496 : :
497 : 210 : seg_vaddr = vaddr;
498 [ + - ]: 210 : seg_len = MAP_PAGE_SIZE;
499 : 10 : } else {
500 [ + - ]: 642373 : seg_len += MAP_PAGE_SIZE;
501 : : }
502 : :
503 [ + - ]: 642583 : vaddr += MAP_PAGE_SIZE;
504 [ + - ]: 642583 : len -= MAP_PAGE_SIZE;
505 : : }
506 : :
507 [ + + ]: 34644 : if (seg_len > 0) {
508 [ + + + - : 104439 : TAILQ_FOREACH_REVERSE(map, &g_spdk_mem_maps, spdk_mem_map_head, tailq) {
+ - + - +
+ + - + -
+ - + - +
- + - ]
509 [ + - + - : 69795 : rc = map->ops.notify_cb(map->cb_ctx, map, SPDK_MEM_MAP_NOTIFY_UNREGISTER,
+ - - + +
- + - +
- ]
510 : 908 : (void *)seg_vaddr, seg_len);
511 [ + + ]: 69795 : if (rc != 0) {
512 [ # # ]: 0 : pthread_mutex_unlock(&g_spdk_mem_map_mutex);
513 : 0 : return rc;
514 : : }
515 : 908 : }
516 : 473 : }
517 : :
518 [ + + ]: 34644 : pthread_mutex_unlock(&g_spdk_mem_map_mutex);
519 : 34644 : return 0;
520 : 481 : }
521 : :
522 : : int
523 : 0 : spdk_mem_reserve(void *vaddr, size_t len)
524 : : {
525 : : struct spdk_mem_map *map;
526 : : void *seg_vaddr;
527 : : size_t seg_len;
528 : : uint64_t reg;
529 : :
530 [ # # # # ]: 0 : if ((uintptr_t)vaddr & ~MASK_256TB) {
531 : 0 : DEBUG_PRINT("invalid usermode virtual address %p\n", vaddr);
532 : 0 : return -EINVAL;
533 : : }
534 : :
535 [ # # # # : 0 : if (((uintptr_t)vaddr & MAP_PAGE_MASK) || (len & MAP_PAGE_MASK)) {
# # # # ]
536 : 0 : DEBUG_PRINT("invalid %s parameters, vaddr=%p len=%ju\n",
537 : : __func__, vaddr, len);
538 : 0 : return -EINVAL;
539 : : }
540 : :
541 [ # # ]: 0 : if (len == 0) {
542 : 0 : return 0;
543 : : }
544 : :
545 [ # # ]: 0 : pthread_mutex_lock(&g_spdk_mem_map_mutex);
546 : :
547 : : /* Check if any part of this range is already registered */
548 : 0 : seg_vaddr = vaddr;
549 : 0 : seg_len = len;
550 [ # # ]: 0 : while (seg_len > 0) {
551 : 0 : reg = spdk_mem_map_translate(g_mem_reg_map, (uint64_t)seg_vaddr, NULL);
552 [ # # # # ]: 0 : if (reg & REG_MAP_REGISTERED) {
553 [ # # ]: 0 : pthread_mutex_unlock(&g_spdk_mem_map_mutex);
554 : 0 : return -EBUSY;
555 : : }
556 [ # # ]: 0 : seg_vaddr += MAP_PAGE_SIZE;
557 [ # # ]: 0 : seg_len -= MAP_PAGE_SIZE;
558 : : }
559 : :
560 : : /* Simply set the translation to the memory map's default. This allocates the space in the
561 : : * map but does not provide a valid translation. */
562 : 0 : spdk_mem_map_set_translation(g_mem_reg_map, (uint64_t)vaddr, len,
563 [ # # # # ]: 0 : g_mem_reg_map->default_translation);
564 : :
565 [ # # # # : 0 : TAILQ_FOREACH(map, &g_spdk_mem_maps, tailq) {
# # # # ]
566 [ # # # # ]: 0 : spdk_mem_map_set_translation(map, (uint64_t)vaddr, len, map->default_translation);
567 : 0 : }
568 : :
569 [ # # ]: 0 : pthread_mutex_unlock(&g_spdk_mem_map_mutex);
570 : 0 : return 0;
571 : 0 : }
572 : :
573 : : static struct map_1gb *
574 : 14000535 : mem_map_get_map_1gb(struct spdk_mem_map *map, uint64_t vfn_page)
575 : : {
576 : : struct map_1gb *map_1gb;
577 [ + + ]: 14000535 : uint64_t idx_256tb = MAP_256TB_IDX(vfn_page);
578 : : size_t i;
579 : :
580 [ + + ]: 14000535 : if (spdk_unlikely(idx_256tb >= SPDK_COUNTOF(map->map_256tb.map))) {
581 : 42 : return NULL;
582 : : }
583 : :
584 [ + - + - : 14000493 : map_1gb = map->map_256tb.map[idx_256tb];
+ - + - ]
585 : :
586 [ + + ]: 14000493 : if (!map_1gb) {
587 [ + + + - ]: 11721 : pthread_mutex_lock(&map->mutex);
588 : :
589 : : /* Recheck to make sure nobody else got the mutex first. */
590 [ + - + - : 11721 : map_1gb = map->map_256tb.map[idx_256tb];
+ - + - ]
591 [ + + ]: 11721 : if (!map_1gb) {
592 [ + - ]: 11721 : map_1gb = malloc(MAP_SIZE_OF_MAP_1GB);
593 [ + - ]: 11721 : if (map_1gb) {
594 : : /* initialize all entries to default translation */
595 [ + + + + ]: 49443785 : for (i = 0; i < MAP_NUM_PAGES_PER_GB; i++) {
596 [ + - + - : 49432064 : map_1gb->map[i].translation = map->default_translation;
+ - + - +
- + - ]
597 : 1680384 : }
598 [ + - + - : 11721 : map->map_256tb.map[idx_256tb] = map_1gb;
+ - + - ]
599 : 216 : }
600 : 216 : }
601 : :
602 [ + + + - ]: 11721 : pthread_mutex_unlock(&map->mutex);
603 : :
604 [ + + ]: 11721 : if (!map_1gb) {
605 : 0 : DEBUG_PRINT("allocation failed\n");
606 : 0 : return NULL;
607 : : }
608 : 216 : }
609 : :
610 : 14000493 : return map_1gb;
611 : 104280 : }
612 : :
613 : : int
614 : 5746685 : spdk_mem_map_set_translation(struct spdk_mem_map *map, uint64_t vaddr, uint64_t size,
615 : : uint64_t translation)
616 : : {
617 : : uint64_t vfn_page;
618 : : struct map_1gb *map_1gb;
619 : : uint64_t idx_1gb;
620 : : struct map_page *map_page;
621 : :
622 [ + + + + ]: 5746685 : if ((uintptr_t)vaddr & ~MASK_256TB) {
623 : 42 : DEBUG_PRINT("invalid usermode virtual address %" PRIu64 "\n", vaddr);
624 : 42 : return -EINVAL;
625 : : }
626 : :
627 : : /* Only page-aligned registrations are supported */
628 [ + + + + : 5746643 : if (((uintptr_t)vaddr & MAP_PAGE_MASK) || (size & MAP_PAGE_MASK)) {
+ - + + ]
629 : 84 : DEBUG_PRINT("invalid %s parameters, vaddr=%" PRIu64 " len=%" PRIu64 "\n",
630 : : __func__, vaddr, size);
631 : 84 : return -EINVAL;
632 : : }
633 : :
634 [ + + ]: 5746559 : vfn_page = vaddr >> MAP_PAGE_SHIFT;
635 : :
636 [ + + ]: 19747052 : while (size) {
637 : 14000535 : map_1gb = mem_map_get_map_1gb(map, vfn_page);
638 [ + + ]: 14000535 : if (!map_1gb) {
639 : 42 : DEBUG_PRINT("could not get %p map\n", (void *)vaddr);
640 : 42 : return -ENOMEM;
641 : : }
642 : :
643 [ + + ]: 14000493 : idx_1gb = MAP_1GB_IDX(vfn_page);
644 [ + - + - ]: 14000493 : map_page = &map_1gb->map[idx_1gb];
645 [ + - + - ]: 14000493 : map_page->translation = translation;
646 : :
647 [ + - ]: 14000493 : size -= MAP_PAGE_SIZE;
648 : 14000493 : vfn_page++;
649 : : }
650 : :
651 : 5746517 : return 0;
652 : 68165 : }
653 : :
654 : : int
655 : 934058 : spdk_mem_map_clear_translation(struct spdk_mem_map *map, uint64_t vaddr, uint64_t size)
656 : : {
657 [ + - + - ]: 934058 : return spdk_mem_map_set_translation(map, vaddr, size, map->default_translation);
658 : : }
659 : :
660 : : inline uint64_t
661 : 150506179 : spdk_mem_map_translate(const struct spdk_mem_map *map, uint64_t vaddr, uint64_t *size)
662 : : {
663 : : const struct map_1gb *map_1gb;
664 : : const struct map_page *map_page;
665 : : uint64_t idx_256tb;
666 : : uint64_t idx_1gb;
667 : : uint64_t vfn_page;
668 : : uint64_t cur_size;
669 : : uint64_t prev_translation;
670 : : uint64_t orig_translation;
671 : :
672 [ + + - + ]: 150506179 : if (spdk_unlikely(vaddr & ~MASK_256TB)) {
673 : 0 : DEBUG_PRINT("invalid usermode virtual address %p\n", (void *)vaddr);
674 [ # # # # ]: 0 : return map->default_translation;
675 : : }
676 : :
677 [ + + ]: 150506179 : vfn_page = vaddr >> MAP_PAGE_SHIFT;
678 [ + + ]: 150506179 : idx_256tb = MAP_256TB_IDX(vfn_page);
679 [ + + ]: 150506179 : idx_1gb = MAP_1GB_IDX(vfn_page);
680 : :
681 [ + - + - : 150506179 : map_1gb = map->map_256tb.map[idx_256tb];
+ - + - ]
682 [ + + ]: 150506179 : if (spdk_unlikely(!map_1gb)) {
683 [ + - + - ]: 2484847 : return map->default_translation;
684 : : }
685 : :
686 [ + - + - ]: 148021332 : cur_size = MAP_PAGE_SIZE - MAP_PAGE_OFFSET(vaddr);
687 [ + - + - ]: 148021332 : map_page = &map_1gb->map[idx_1gb];
688 [ + + + + : 148021532 : if (size == NULL || map->ops.are_contiguous == NULL ||
+ - + - +
+ + + ]
689 [ + + + - : 63847324 : map_page->translation == map->default_translation) {
+ - + - ]
690 [ + + ]: 84174050 : if (size != NULL) {
691 [ + - + + : 420 : *size = spdk_min(*size, cur_size);
+ - + - ]
692 : 20 : }
693 [ + - + - ]: 84174050 : return map_page->translation;
694 : : }
695 : :
696 [ + - + - ]: 63847282 : orig_translation = map_page->translation;
697 : 63847282 : prev_translation = orig_translation;
698 [ + + + + ]: 63937332 : while (cur_size < *size) {
699 : 160026 : vfn_page++;
700 [ + + ]: 160026 : idx_256tb = MAP_256TB_IDX(vfn_page);
701 [ + + ]: 160026 : idx_1gb = MAP_1GB_IDX(vfn_page);
702 : :
703 [ + - + - : 160026 : map_1gb = map->map_256tb.map[idx_256tb];
+ - + - ]
704 [ + + ]: 160026 : if (spdk_unlikely(!map_1gb)) {
705 : 0 : break;
706 : : }
707 : :
708 [ + - + - ]: 160026 : map_page = &map_1gb->map[idx_1gb];
709 [ + + + - : 160026 : if (!map->ops.are_contiguous(prev_translation, map_page->translation)) {
+ - - + +
- + - + -
+ + ]
710 : 69976 : break;
711 : : }
712 : :
713 [ + - ]: 90050 : cur_size += MAP_PAGE_SIZE;
714 [ + - + - ]: 90050 : prev_translation = map_page->translation;
715 : : }
716 : :
717 [ + - + + : 63847282 : *size = spdk_min(*size, cur_size);
- + + - ]
718 : 63847282 : return orig_translation;
719 : 44715 : }
720 : :
721 : : static void
722 : 68682 : memory_hotplug_cb(enum rte_mem_event event_type,
723 : : const void *addr, size_t len, void *arg)
724 : : {
725 [ + + ]: 68682 : if (event_type == RTE_MEM_EVENT_ALLOC) {
726 : 35180 : spdk_mem_register((void *)addr, len);
727 : :
728 [ + + ]: 35180 : if (!spdk_env_dpdk_external_init()) {
729 : 35159 : return;
730 : : }
731 : :
732 : : /* When the user initialized DPDK separately, we can't
733 : : * be sure that --match-allocations RTE flag was specified.
734 : : * Without this flag, DPDK can free memory in different units
735 : : * than it was allocated. It doesn't work with things like RDMA MRs.
736 : : *
737 : : * For such cases, we mark segments so they aren't freed.
738 : : */
739 [ + + ]: 48 : while (len > 0) {
740 : : struct rte_memseg *seg;
741 : :
742 : 27 : seg = rte_mem_virt2memseg(addr, NULL);
743 [ + + # # ]: 27 : assert(seg != NULL);
744 [ + - + - : 27 : seg->flags |= RTE_MEMSEG_FLAG_DO_NOT_FREE;
+ - ]
745 [ + - + - ]: 27 : addr = (void *)((uintptr_t)addr + seg->hugepage_sz);
746 [ + - + - ]: 27 : len -= seg->hugepage_sz;
747 : : }
748 [ + + ]: 33503 : } else if (event_type == RTE_MEM_EVENT_FREE) {
749 : 33502 : spdk_mem_unregister((void *)addr, len);
750 : 445 : }
751 : 898 : }
752 : :
753 : : static int
754 : 2734 : memory_iter_cb(const struct rte_memseg_list *msl,
755 : : const struct rte_memseg *ms, size_t len, void *arg)
756 : : {
757 [ + - + - : 2734 : return spdk_mem_register(ms->addr, len);
+ - ]
758 : : }
759 : :
760 : : int
761 : 2752 : mem_map_init(bool legacy_mem)
762 : : {
763 : : int rc;
764 : :
765 [ + - ]: 2752 : g_legacy_mem = legacy_mem;
766 : :
767 : 2752 : g_mem_reg_map = spdk_mem_map_alloc(0, NULL, NULL);
768 [ - + ]: 2752 : if (g_mem_reg_map == NULL) {
769 : 0 : DEBUG_PRINT("memory registration map allocation failed\n");
770 : 0 : return -ENOMEM;
771 : : }
772 : :
773 [ + + + + ]: 2752 : if (g_huge_pages) {
774 : 2744 : rc = rte_mem_event_callback_register("spdk", memory_hotplug_cb, NULL);
775 [ - + ]: 2744 : if (rc != 0) {
776 : 0 : DEBUG_PRINT("memory event callback registration failed, rc = %d\n", rc);
777 : 0 : goto err_free_reg_map;
778 : : }
779 : 2744 : g_mem_event_cb_registered = true;
780 : 68 : }
781 : :
782 : : /*
783 : : * Walk all DPDK memory segments and register them
784 : : * with the main memory map
785 : : */
786 : 2752 : rc = rte_memseg_contig_walk(memory_iter_cb, NULL);
787 [ - + ]: 2752 : if (rc != 0) {
788 : 0 : DEBUG_PRINT("memory segments walking failed, rc = %d\n", rc);
789 : 0 : goto err_unregister_mem_cb;
790 : : }
791 : :
792 : 2752 : return 0;
793 : :
794 : 0 : err_unregister_mem_cb:
795 [ # # # # ]: 0 : if (g_mem_event_cb_registered) {
796 : 0 : g_mem_event_cb_registered = false;
797 : 0 : rte_mem_event_callback_unregister("spdk", NULL);
798 : 0 : }
799 : 0 : err_free_reg_map:
800 : 0 : spdk_mem_map_free(&g_mem_reg_map);
801 : 0 : return rc;
802 : 68 : }
803 : :
804 : : void
805 : 2693 : mem_map_fini(void)
806 : : {
807 [ + + + + ]: 2693 : if (g_mem_event_cb_registered) {
808 : 2601 : g_mem_event_cb_registered = false;
809 : 2601 : rte_mem_event_callback_unregister("spdk", NULL);
810 : 66 : }
811 : 2693 : spdk_mem_map_free(&g_mem_reg_map);
812 : 2693 : }
813 : :
814 : : bool
815 : 21537 : spdk_iommu_is_enabled(void)
816 : : {
817 : : #if VFIO_ENABLED
818 [ + + + + : 21537 : return g_vfio.enabled && !g_vfio.noiommu_enabled;
+ + + - ]
819 : : #else
820 : : return false;
821 : : #endif
822 : : }
823 : :
824 : : struct spdk_vtophys_pci_device {
825 : : struct rte_pci_device *pci_device;
826 : : TAILQ_ENTRY(spdk_vtophys_pci_device) tailq;
827 : : };
828 : :
829 : : static pthread_mutex_t g_vtophys_pci_devices_mutex = PTHREAD_MUTEX_INITIALIZER;
830 : : static TAILQ_HEAD(, spdk_vtophys_pci_device) g_vtophys_pci_devices =
831 : : TAILQ_HEAD_INITIALIZER(g_vtophys_pci_devices);
832 : :
833 : : static struct spdk_mem_map *g_vtophys_map = NULL;
834 : : static struct spdk_mem_map *g_phys_ref_map = NULL;
835 : : static struct spdk_mem_map *g_numa_map = NULL;
836 : :
837 : : #if VFIO_ENABLED
838 : : static int
839 : 771 : _vfio_iommu_map_dma(uint64_t vaddr, uint64_t iova, uint64_t size)
840 : : {
841 : : struct spdk_vfio_dma_map *dma_map;
842 : : int ret;
843 : :
844 : 771 : dma_map = calloc(1, sizeof(*dma_map));
845 [ + + ]: 771 : if (dma_map == NULL) {
846 : 0 : return -ENOMEM;
847 : : }
848 : :
849 [ + - + - : 771 : dma_map->map.argsz = sizeof(dma_map->map);
+ - ]
850 [ - + + - : 771 : dma_map->map.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;
- + + - +
- + - +
- ]
851 [ + - + - : 771 : dma_map->map.vaddr = vaddr;
+ - ]
852 [ + - + - : 771 : dma_map->map.iova = iova;
+ - ]
853 [ + - + - : 771 : dma_map->map.size = size;
+ - ]
854 : :
855 [ + + - + ]: 771 : if (g_vfio.device_ref == 0) {
856 : : /* VFIO requires at least one device (IOMMU group) to be added to
857 : : * a VFIO container before it is possible to perform any IOMMU
858 : : * operations on that container. This memory will be mapped once
859 : : * the first device (IOMMU group) is hotplugged.
860 : : *
861 : : * Since the vfio container is managed internally by DPDK, it is
862 : : * also possible that some device is already in that container, but
863 : : * it's not managed by SPDK - e.g. an NIC attached internally
864 : : * inside DPDK. We could map the memory straight away in such
865 : : * scenario, but there's no need to do it. DPDK devices clearly
866 : : * don't need our mappings and hence we defer the mapping
867 : : * unconditionally until the first SPDK-managed device is
868 : : * hotplugged.
869 : : */
870 : 659 : goto out_insert;
871 : : }
872 : :
873 [ # # # # : 112 : ret = ioctl(g_vfio.fd, VFIO_IOMMU_MAP_DMA, &dma_map->map);
# # # # #
# # # # #
# # ]
874 [ + - ]: 112 : if (ret) {
875 : : /* There are cases the vfio container doesn't have IOMMU group, it's safe for this case */
876 [ # # ]: 0 : SPDK_NOTICELOG("Cannot set up DMA mapping, error %d, ignored\n", errno);
877 : 0 : }
878 : :
879 : 112 : out_insert:
880 [ + - + - : 771 : TAILQ_INSERT_TAIL(&g_vfio.maps, dma_map, tailq);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
881 : 771 : return 0;
882 : 2 : }
883 : :
884 : :
885 : : static int
886 : 215 : vtophys_iommu_map_dma(uint64_t vaddr, uint64_t iova, uint64_t size)
887 : : {
888 : : uint64_t refcount;
889 : : int ret;
890 : :
891 : 215 : refcount = spdk_mem_map_translate(g_phys_ref_map, iova, NULL);
892 [ - + # # ]: 215 : assert(refcount < UINT64_MAX);
893 [ - + ]: 215 : if (refcount > 0) {
894 : 0 : spdk_mem_map_set_translation(g_phys_ref_map, iova, size, refcount + 1);
895 : 0 : return 0;
896 : : }
897 : :
898 [ - + ]: 215 : pthread_mutex_lock(&g_vfio.mutex);
899 : 215 : ret = _vfio_iommu_map_dma(vaddr, iova, size);
900 [ - + ]: 215 : pthread_mutex_unlock(&g_vfio.mutex);
901 [ - + ]: 215 : if (ret) {
902 : 0 : return ret;
903 : : }
904 : :
905 : 215 : spdk_mem_map_set_translation(g_phys_ref_map, iova, size, refcount + 1);
906 : 215 : return 0;
907 : 0 : }
908 : :
909 : : int
910 : 556 : vtophys_iommu_map_dma_bar(uint64_t vaddr, uint64_t iova, uint64_t size)
911 : : {
912 : : int ret;
913 : :
914 [ + + ]: 556 : pthread_mutex_lock(&g_vfio.mutex);
915 : 556 : ret = _vfio_iommu_map_dma(vaddr, iova, size);
916 [ + + ]: 556 : pthread_mutex_unlock(&g_vfio.mutex);
917 : :
918 : 556 : return ret;
919 : : }
920 : :
921 : : static int
922 : 747 : _vfio_iommu_unmap_dma(struct spdk_vfio_dma_map *dma_map)
923 : : {
924 : 747 : struct vfio_iommu_type1_dma_unmap unmap = {};
925 : : int ret;
926 : :
927 [ + + - + ]: 747 : if (g_vfio.device_ref == 0) {
928 : : /* Memory is not mapped anymore, just remove it's references */
929 : 103 : goto out_remove;
930 : : }
931 : :
932 : 644 : unmap.argsz = sizeof(unmap);
933 [ + - ]: 644 : unmap.flags = 0;
934 [ + - + - : 644 : unmap.iova = dma_map->map.iova;
+ - + - ]
935 [ + - + - : 644 : unmap.size = dma_map->map.size;
+ - + - ]
936 [ + - - + : 644 : ret = ioctl(g_vfio.fd, VFIO_IOMMU_UNMAP_DMA, &unmap);
+ - - + +
- - + +
- ]
937 [ + - ]: 644 : if (ret) {
938 [ # # ]: 0 : SPDK_NOTICELOG("Cannot clear DMA mapping, error %d, ignored\n", errno);
939 : 0 : }
940 : :
941 : 691 : out_remove:
942 [ + + + - : 747 : TAILQ_REMOVE(&g_vfio.maps, dma_map, tailq);
+ - + - #
# # # # #
# # # # #
# # # # #
# # + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
943 : 747 : free(dma_map);
944 : 747 : return 0;
945 : : }
946 : :
947 : : static int
948 : 215 : vtophys_iommu_unmap_dma(uint64_t iova, uint64_t size)
949 : : {
950 : : struct spdk_vfio_dma_map *dma_map;
951 : : uint64_t refcount;
952 : : int ret;
953 : :
954 [ - + ]: 215 : pthread_mutex_lock(&g_vfio.mutex);
955 [ + - # # : 506 : TAILQ_FOREACH(dma_map, &g_vfio.maps, tailq) {
# # # # #
# # # ]
956 [ + + # # : 506 : if (dma_map->map.iova == iova) {
# # # # ]
957 : 215 : break;
958 : : }
959 : 0 : }
960 : :
961 [ - + ]: 215 : if (dma_map == NULL) {
962 : 0 : DEBUG_PRINT("Cannot clear DMA mapping for IOVA %"PRIx64" - it's not mapped\n", iova);
963 [ # # ]: 0 : pthread_mutex_unlock(&g_vfio.mutex);
964 : 0 : return -ENXIO;
965 : : }
966 : :
967 : 215 : refcount = spdk_mem_map_translate(g_phys_ref_map, iova, NULL);
968 [ - + # # ]: 215 : assert(refcount < UINT64_MAX);
969 [ + - ]: 215 : if (refcount > 0) {
970 : 215 : spdk_mem_map_set_translation(g_phys_ref_map, iova, size, refcount - 1);
971 : 0 : }
972 : :
973 : : /* We still have outstanding references, don't clear it. */
974 [ - + ]: 215 : if (refcount > 1) {
975 [ # # ]: 0 : pthread_mutex_unlock(&g_vfio.mutex);
976 : 0 : return 0;
977 : : }
978 : :
979 : : /** don't support partial or multiple-page unmap for now */
980 [ - + # # : 215 : assert(dma_map->map.size == size);
# # # # #
# ]
981 : :
982 : 215 : ret = _vfio_iommu_unmap_dma(dma_map);
983 [ - + ]: 215 : pthread_mutex_unlock(&g_vfio.mutex);
984 : :
985 : 215 : return ret;
986 : 0 : }
987 : :
988 : : int
989 : 532 : vtophys_iommu_unmap_dma_bar(uint64_t vaddr)
990 : : {
991 : : struct spdk_vfio_dma_map *dma_map;
992 : : int ret;
993 : :
994 [ + + ]: 532 : pthread_mutex_lock(&g_vfio.mutex);
995 [ + - + - : 541 : TAILQ_FOREACH(dma_map, &g_vfio.maps, tailq) {
- + # # #
# # # ]
996 [ + + + - : 541 : if (dma_map->map.vaddr == vaddr) {
+ - - + ]
997 : 532 : break;
998 : : }
999 : 0 : }
1000 : :
1001 [ + + ]: 532 : if (dma_map == NULL) {
1002 : 0 : DEBUG_PRINT("Cannot clear DMA mapping for address %"PRIx64" - it's not mapped\n", vaddr);
1003 [ # # ]: 0 : pthread_mutex_unlock(&g_vfio.mutex);
1004 : 0 : return -ENXIO;
1005 : : }
1006 : :
1007 : 532 : ret = _vfio_iommu_unmap_dma(dma_map);
1008 [ + + ]: 532 : pthread_mutex_unlock(&g_vfio.mutex);
1009 : 532 : return ret;
1010 : 2 : }
1011 : : #endif
1012 : :
1013 : : static uint64_t
1014 : 1032321 : vtophys_get_paddr_memseg(uint64_t vaddr)
1015 : : {
1016 : : uintptr_t paddr;
1017 : : struct rte_memseg *seg;
1018 : :
1019 : 1032321 : seg = rte_mem_virt2memseg((void *)(uintptr_t)vaddr, NULL);
1020 [ + + ]: 1032321 : if (seg != NULL) {
1021 [ + - + - ]: 1031209 : paddr = seg->iova;
1022 [ + + ]: 1031209 : if (paddr == RTE_BAD_IOVA) {
1023 : 0 : return SPDK_VTOPHYS_ERROR;
1024 : : }
1025 [ + - + - : 1031209 : paddr += (vaddr - (uintptr_t)seg->addr);
+ - ]
1026 : 1031209 : return paddr;
1027 : : }
1028 : :
1029 : 1112 : return SPDK_VTOPHYS_ERROR;
1030 : 19609 : }
1031 : :
1032 : : /* Try to get the paddr from /proc/self/pagemap */
1033 : : static uint64_t
1034 : 16571 : vtophys_get_paddr_pagemap(uint64_t vaddr)
1035 : : {
1036 : : uintptr_t paddr;
1037 : :
1038 : : /* Silence static analyzers */
1039 [ - + # # ]: 16571 : assert(vaddr != 0);
1040 : 16571 : paddr = rte_mem_virt2iova((void *)vaddr);
1041 [ + + ]: 16571 : if (paddr == RTE_BAD_IOVA) {
1042 : : /*
1043 : : * The vaddr may be valid but doesn't have a backing page
1044 : : * assigned yet. Touch the page to ensure a backing page
1045 : : * gets assigned, then try to translate again.
1046 : : */
1047 : 1174 : rte_atomic64_read((rte_atomic64_t *)vaddr);
1048 : 1174 : paddr = rte_mem_virt2iova((void *)vaddr);
1049 : 0 : }
1050 [ + + ]: 16571 : if (paddr == RTE_BAD_IOVA) {
1051 : : /* Unable to get to the physical address. */
1052 : 2 : return SPDK_VTOPHYS_ERROR;
1053 : : }
1054 : :
1055 : 16569 : return paddr;
1056 : 0 : }
1057 : :
1058 : : static uint64_t
1059 : 3164 : pci_device_vtophys(struct rte_pci_device *dev, uint64_t vaddr, size_t len)
1060 : : {
1061 : : struct rte_mem_resource *res;
1062 : : uint64_t paddr;
1063 : : unsigned r;
1064 : :
1065 [ + + ]: 18308 : for (r = 0; r < PCI_MAX_RESOURCE; r++) {
1066 : 16808 : res = dpdk_pci_device_get_mem_resource(dev, r);
1067 : :
1068 [ + + + + : 16808 : if (res->phys_addr == 0 || vaddr < (uint64_t)res->addr ||
# # # # #
# # # #
# ]
1069 [ + + # # : 6500 : (vaddr + len) >= (uint64_t)res->addr + res->len) {
# # # # ]
1070 : 15144 : continue;
1071 : : }
1072 : :
1073 : : #if VFIO_ENABLED
1074 [ - + - - ]: 1664 : if (spdk_iommu_is_enabled() && rte_eal_iova_mode() == RTE_IOVA_VA) {
1075 : : /*
1076 : : * The IOMMU is on and we're using IOVA == VA. The BAR was
1077 : : * automatically registered when it was mapped, so just return
1078 : : * the virtual address here.
1079 : : */
1080 : 0 : return vaddr;
1081 : : }
1082 : : #endif
1083 [ # # # # : 1664 : paddr = res->phys_addr + (vaddr - (uint64_t)res->addr);
# # # # ]
1084 : 1664 : return paddr;
1085 : : }
1086 : :
1087 : 1500 : return SPDK_VTOPHYS_ERROR;
1088 : 0 : }
1089 : :
1090 : : /* Try to get the paddr from pci devices */
1091 : : static uint64_t
1092 : 2684 : vtophys_get_paddr_pci(uint64_t vaddr, size_t len)
1093 : : {
1094 : : struct spdk_vtophys_pci_device *vtophys_dev;
1095 : : uintptr_t paddr;
1096 : : struct rte_pci_device *dev;
1097 : :
1098 [ - + ]: 2684 : pthread_mutex_lock(&g_vtophys_pci_devices_mutex);
1099 [ + + # # : 4184 : TAILQ_FOREACH(vtophys_dev, &g_vtophys_pci_devices, tailq) {
# # # # ]
1100 [ # # # # ]: 3164 : dev = vtophys_dev->pci_device;
1101 : 3164 : paddr = pci_device_vtophys(dev, vaddr, len);
1102 [ + + ]: 3164 : if (paddr != SPDK_VTOPHYS_ERROR) {
1103 [ # # ]: 1664 : pthread_mutex_unlock(&g_vtophys_pci_devices_mutex);
1104 : 1664 : return paddr;
1105 : : }
1106 : 0 : }
1107 [ - + ]: 1020 : pthread_mutex_unlock(&g_vtophys_pci_devices_mutex);
1108 : :
1109 : 1020 : return SPDK_VTOPHYS_ERROR;
1110 : 0 : }
1111 : :
1112 : : static int
1113 : 76770 : vtophys_notify(void *cb_ctx, struct spdk_mem_map *map,
1114 : : enum spdk_mem_map_notify_action action,
1115 : : void *vaddr, size_t len)
1116 : : {
1117 : 76770 : int rc = 0;
1118 : : uint64_t paddr;
1119 : :
1120 [ + + - + ]: 76770 : if ((uintptr_t)vaddr & ~MASK_256TB) {
1121 : 0 : DEBUG_PRINT("invalid usermode virtual address %p\n", vaddr);
1122 : 0 : return -EINVAL;
1123 : : }
1124 : :
1125 [ + - + + : 76770 : if (((uintptr_t)vaddr & MASK_2MB) || (len & MASK_2MB)) {
+ - - + ]
1126 : 0 : DEBUG_PRINT("invalid parameters, vaddr=%p len=%ju\n",
1127 : : vaddr, len);
1128 : 0 : return -EINVAL;
1129 : : }
1130 : :
1131 : : /* Get the physical address from the DPDK memsegs */
1132 : 76770 : paddr = vtophys_get_paddr_memseg((uint64_t)vaddr);
1133 : :
1134 [ + + + ]: 76770 : switch (action) {
1135 : 37943 : case SPDK_MEM_MAP_NOTIFY_REGISTER:
1136 [ + + ]: 38462 : if (paddr == SPDK_VTOPHYS_ERROR) {
1137 : : /* This is not an address that DPDK is managing. */
1138 : :
1139 : : /* Check if this is a PCI BAR. They need special handling */
1140 : 556 : paddr = vtophys_get_paddr_pci((uint64_t)vaddr, len);
1141 [ + + ]: 556 : if (paddr != SPDK_VTOPHYS_ERROR) {
1142 : : /* Get paddr for each 2MB chunk in this address range */
1143 [ + + ]: 832 : while (len > 0) {
1144 [ # # ]: 786 : paddr = vtophys_get_paddr_pci((uint64_t)vaddr, VALUE_2MB);
1145 [ - + ]: 786 : if (paddr == SPDK_VTOPHYS_ERROR) {
1146 : 0 : DEBUG_PRINT("could not get phys addr for %p\n", vaddr);
1147 : 0 : return -EFAULT;
1148 : : }
1149 : :
1150 [ # # ]: 786 : rc = spdk_mem_map_set_translation(map, (uint64_t)vaddr, VALUE_2MB, paddr);
1151 [ - + ]: 786 : if (rc != 0) {
1152 : 0 : return rc;
1153 : : }
1154 : :
1155 [ # # ]: 786 : vaddr += VALUE_2MB;
1156 [ # # ]: 786 : len -= VALUE_2MB;
1157 : : }
1158 : :
1159 : 46 : return 0;
1160 : : }
1161 : :
1162 : : #if VFIO_ENABLED
1163 : : enum rte_iova_mode iova_mode;
1164 : :
1165 : 510 : iova_mode = rte_eal_iova_mode();
1166 : :
1167 [ + + + - ]: 725 : if (spdk_iommu_is_enabled() && iova_mode == RTE_IOVA_VA) {
1168 : : /* We'll use the virtual address as the iova to match DPDK. */
1169 : 215 : paddr = (uint64_t)vaddr;
1170 : 215 : rc = vtophys_iommu_map_dma((uint64_t)vaddr, paddr, len);
1171 [ - + ]: 215 : if (rc) {
1172 : 0 : return -EFAULT;
1173 : : }
1174 [ + + ]: 41326 : while (len > 0) {
1175 [ # # ]: 41111 : rc = spdk_mem_map_set_translation(map, (uint64_t)vaddr, VALUE_2MB, paddr);
1176 [ - + ]: 41111 : if (rc != 0) {
1177 : 0 : return rc;
1178 : : }
1179 [ # # ]: 41111 : vaddr += VALUE_2MB;
1180 [ # # ]: 41111 : paddr += VALUE_2MB;
1181 [ # # ]: 41111 : len -= VALUE_2MB;
1182 : : }
1183 : 0 : } else
1184 : : #endif
1185 : : {
1186 : : /* Get the physical address from /proc/self/pagemap. */
1187 : 295 : paddr = vtophys_get_paddr_pagemap((uint64_t)vaddr);
1188 [ + + ]: 295 : if (paddr == SPDK_VTOPHYS_ERROR) {
1189 : 2 : DEBUG_PRINT("could not get phys addr for %p\n", vaddr);
1190 : 2 : return -EFAULT;
1191 : : }
1192 : :
1193 : : /* Get paddr for each 2MB chunk in this address range */
1194 [ + + ]: 16569 : while (len > 0) {
1195 : : /* Get the physical address from /proc/self/pagemap. */
1196 : 16276 : paddr = vtophys_get_paddr_pagemap((uint64_t)vaddr);
1197 : :
1198 [ - + ]: 16276 : if (paddr == SPDK_VTOPHYS_ERROR) {
1199 : 0 : DEBUG_PRINT("could not get phys addr for %p\n", vaddr);
1200 : 0 : return -EFAULT;
1201 : : }
1202 : :
1203 [ - + # # ]: 16276 : if (paddr & MASK_2MB) {
1204 : 0 : DEBUG_PRINT("invalid paddr 0x%" PRIx64 " - must be 2MB aligned\n", paddr);
1205 : 0 : return -EINVAL;
1206 : : }
1207 : : #if VFIO_ENABLED
1208 : : /* If the IOMMU is on, but DPDK is using iova-mode=pa, we want to register this memory
1209 : : * with the IOMMU using the physical address to match. */
1210 [ - + ]: 16276 : if (spdk_iommu_is_enabled()) {
1211 [ # # ]: 0 : rc = vtophys_iommu_map_dma((uint64_t)vaddr, paddr, VALUE_2MB);
1212 [ # # ]: 0 : if (rc) {
1213 : 0 : DEBUG_PRINT("Unable to assign vaddr %p to paddr 0x%" PRIx64 "\n", vaddr, paddr);
1214 : 0 : return -EFAULT;
1215 : : }
1216 : 0 : }
1217 : : #endif
1218 : :
1219 [ # # ]: 16276 : rc = spdk_mem_map_set_translation(map, (uint64_t)vaddr, VALUE_2MB, paddr);
1220 [ - + ]: 16276 : if (rc != 0) {
1221 : 0 : return rc;
1222 : : }
1223 : :
1224 [ # # ]: 16276 : vaddr += VALUE_2MB;
1225 [ # # ]: 16276 : len -= VALUE_2MB;
1226 : : }
1227 : : }
1228 : 0 : } else {
1229 : : /* This is an address managed by DPDK. Just setup the translations. */
1230 [ + + ]: 993457 : while (len > 0) {
1231 : 955551 : paddr = vtophys_get_paddr_memseg((uint64_t)vaddr);
1232 [ - + ]: 955551 : if (paddr == SPDK_VTOPHYS_ERROR) {
1233 : 0 : DEBUG_PRINT("could not get phys addr for %p\n", vaddr);
1234 : 0 : return -EFAULT;
1235 : : }
1236 : :
1237 [ + - ]: 955551 : rc = spdk_mem_map_set_translation(map, (uint64_t)vaddr, VALUE_2MB, paddr);
1238 [ - + ]: 955551 : if (rc != 0) {
1239 : 0 : return rc;
1240 : : }
1241 : :
1242 [ + - ]: 955551 : vaddr += VALUE_2MB;
1243 [ + - ]: 955551 : len -= VALUE_2MB;
1244 : : }
1245 : : }
1246 : :
1247 : 38414 : break;
1248 : 37791 : case SPDK_MEM_MAP_NOTIFY_UNREGISTER:
1249 : : #if VFIO_ENABLED
1250 [ + + ]: 38308 : if (paddr == SPDK_VTOPHYS_ERROR) {
1251 : : /*
1252 : : * This is not an address that DPDK is managing.
1253 : : */
1254 : :
1255 : : /* Check if this is a PCI BAR. They need special handling */
1256 : 556 : paddr = vtophys_get_paddr_pci((uint64_t)vaddr, len);
1257 [ + + ]: 556 : if (paddr != SPDK_VTOPHYS_ERROR) {
1258 : : /* Get paddr for each 2MB chunk in this address range */
1259 [ + + ]: 832 : while (len > 0) {
1260 [ # # ]: 786 : paddr = vtophys_get_paddr_pci((uint64_t)vaddr, VALUE_2MB);
1261 [ - + ]: 786 : if (paddr == SPDK_VTOPHYS_ERROR) {
1262 : 0 : DEBUG_PRINT("could not get phys addr for %p\n", vaddr);
1263 : 0 : return -EFAULT;
1264 : : }
1265 : :
1266 [ # # ]: 786 : rc = spdk_mem_map_clear_translation(map, (uint64_t)vaddr, VALUE_2MB);
1267 [ - + ]: 786 : if (rc != 0) {
1268 : 0 : return rc;
1269 : : }
1270 : :
1271 [ # # ]: 786 : vaddr += VALUE_2MB;
1272 [ # # ]: 786 : len -= VALUE_2MB;
1273 : : }
1274 : :
1275 : 46 : return 0;
1276 : : }
1277 : :
1278 : : /* If vfio is enabled,
1279 : : * we need to unmap the range from the IOMMU
1280 : : */
1281 [ + + ]: 510 : if (spdk_iommu_is_enabled()) {
1282 : 215 : uint64_t buffer_len = len;
1283 : 215 : uint8_t *va = vaddr;
1284 : : enum rte_iova_mode iova_mode;
1285 : :
1286 : 215 : iova_mode = rte_eal_iova_mode();
1287 : : /*
1288 : : * In virtual address mode, the region is contiguous and can be done in
1289 : : * one unmap.
1290 : : */
1291 [ + - ]: 215 : if (iova_mode == RTE_IOVA_VA) {
1292 : 215 : paddr = spdk_mem_map_translate(map, (uint64_t)va, &buffer_len);
1293 [ + - - + ]: 215 : if (buffer_len != len || paddr != (uintptr_t)va) {
1294 : 0 : DEBUG_PRINT("Unmapping %p with length %lu failed because "
1295 : : "translation had address 0x%" PRIx64 " and length %lu\n",
1296 : : va, len, paddr, buffer_len);
1297 : 0 : return -EINVAL;
1298 : : }
1299 : 215 : rc = vtophys_iommu_unmap_dma(paddr, len);
1300 [ - + ]: 215 : if (rc) {
1301 : 0 : DEBUG_PRINT("Failed to iommu unmap paddr 0x%" PRIx64 "\n", paddr);
1302 : 0 : return -EFAULT;
1303 : : }
1304 [ # # ]: 0 : } else if (iova_mode == RTE_IOVA_PA) {
1305 : : /* Get paddr for each 2MB chunk in this address range */
1306 [ # # ]: 0 : while (buffer_len > 0) {
1307 : 0 : paddr = spdk_mem_map_translate(map, (uint64_t)va, NULL);
1308 : :
1309 [ # # # # : 0 : if (paddr == SPDK_VTOPHYS_ERROR || buffer_len < VALUE_2MB) {
# # ]
1310 : 0 : DEBUG_PRINT("could not get phys addr for %p\n", va);
1311 : 0 : return -EFAULT;
1312 : : }
1313 : :
1314 [ # # ]: 0 : rc = vtophys_iommu_unmap_dma(paddr, VALUE_2MB);
1315 [ # # ]: 0 : if (rc) {
1316 : 0 : DEBUG_PRINT("Failed to iommu unmap paddr 0x%" PRIx64 "\n", paddr);
1317 : 0 : return -EFAULT;
1318 : : }
1319 : :
1320 [ # # # # ]: 0 : va += VALUE_2MB;
1321 [ # # ]: 0 : buffer_len -= VALUE_2MB;
1322 : : }
1323 : 0 : }
1324 : 0 : }
1325 : 0 : }
1326 : : #endif
1327 [ + + ]: 928102 : while (len > 0) {
1328 [ + - ]: 889840 : rc = spdk_mem_map_clear_translation(map, (uint64_t)vaddr, VALUE_2MB);
1329 [ - + ]: 889840 : if (rc != 0) {
1330 : 0 : return rc;
1331 : : }
1332 : :
1333 [ + - ]: 889840 : vaddr += VALUE_2MB;
1334 [ + - ]: 889840 : len -= VALUE_2MB;
1335 : : }
1336 : :
1337 : 38262 : break;
1338 : 0 : default:
1339 [ # # ]: 0 : SPDK_UNREACHABLE();
1340 : : }
1341 : :
1342 : 76676 : return rc;
1343 : 1036 : }
1344 : :
1345 : : static int
1346 : 76786 : numa_notify(void *cb_ctx, struct spdk_mem_map *map,
1347 : : enum spdk_mem_map_notify_action action,
1348 : : void *vaddr, size_t len)
1349 : : {
1350 : : struct rte_memseg *seg;
1351 : :
1352 : : /* We always return 0 from here, even if we aren't able to get a
1353 : : * memseg for the address. This can happen in non-DPDK memory
1354 : : * registration paths, for example vhost or vfio-user. That is OK,
1355 : : * spdk_mem_get_numa_id() just returns SPDK_ENV_NUMA_ID_ANY for
1356 : : * that kind of memory. If we return an error here, the
1357 : : * spdk_mem_register() from vhost or vfio-user would fail which is
1358 : : * not what we want.
1359 : : */
1360 : 76786 : seg = rte_mem_virt2memseg(vaddr, NULL);
1361 [ + + ]: 76786 : if (seg == NULL) {
1362 : 1112 : return 0;
1363 : : }
1364 : :
1365 [ + + + ]: 75674 : switch (action) {
1366 : 37395 : case SPDK_MEM_MAP_NOTIFY_REGISTER:
1367 [ - + - + ]: 37914 : spdk_mem_map_set_translation(map, (uint64_t)vaddr, len, seg->socket_id);
1368 : 37914 : break;
1369 : 37243 : case SPDK_MEM_MAP_NOTIFY_UNREGISTER:
1370 : 37760 : spdk_mem_map_clear_translation(map, (uint64_t)vaddr, len);
1371 : 37760 : break;
1372 : 0 : default:
1373 : 0 : break;
1374 : : }
1375 : :
1376 : 75674 : return 0;
1377 : 1036 : }
1378 : :
1379 : : static int
1380 : 156129 : vtophys_check_contiguous_entries(uint64_t paddr1, uint64_t paddr2)
1381 : : {
1382 : : /* This function is always called with paddrs for two subsequent
1383 : : * 2MB chunks in virtual address space, so those chunks will be only
1384 : : * physically contiguous if the physical addresses are 2MB apart
1385 : : * from each other as well.
1386 : : */
1387 [ + - ]: 156129 : return (paddr2 - paddr1 == VALUE_2MB);
1388 : : }
1389 : :
1390 : : #if VFIO_ENABLED
1391 : :
1392 : : static bool
1393 : 2710 : vfio_enabled(void)
1394 : : {
1395 : 2710 : return rte_vfio_is_enabled("vfio_pci");
1396 : : }
1397 : :
1398 : : /* Check if IOMMU is enabled on the system */
1399 : : static bool
1400 : 1067 : has_iommu_groups(void)
1401 : : {
1402 : 1067 : int count = 0;
1403 [ + + ]: 1067 : DIR *dir = opendir("/sys/kernel/iommu_groups");
1404 : :
1405 [ + + ]: 1067 : if (dir == NULL) {
1406 : 0 : return false;
1407 : : }
1408 : :
1409 [ + + + + : 4080 : while (count < 3 && readdir(dir) != NULL) {
+ + ]
1410 [ + - ]: 3013 : count++;
1411 : : }
1412 : :
1413 [ + + ]: 1067 : closedir(dir);
1414 : : /* there will always be ./ and ../ entries */
1415 : 1067 : return count > 2;
1416 : 66 : }
1417 : :
1418 : : static bool
1419 : 1067 : vfio_noiommu_enabled(void)
1420 : : {
1421 : 1067 : return rte_vfio_noiommu_is_enabled();
1422 : : }
1423 : :
1424 : : static void
1425 : 2710 : vtophys_iommu_init(void)
1426 : : {
1427 : 1034 : char proc_fd_path[PATH_MAX + 1];
1428 : 1034 : char link_path[PATH_MAX + 1];
1429 : 2710 : const char vfio_path[] = "/dev/vfio/vfio";
1430 : : DIR *dir;
1431 : : struct dirent *d;
1432 : :
1433 [ + + ]: 2710 : if (!vfio_enabled()) {
1434 : 1643 : return;
1435 : : }
1436 : :
1437 [ - + ]: 1067 : if (vfio_noiommu_enabled()) {
1438 : 0 : g_vfio.noiommu_enabled = true;
1439 [ + + ]: 1067 : } else if (!has_iommu_groups()) {
1440 : 188 : return;
1441 : : }
1442 : :
1443 [ + - ]: 879 : dir = opendir("/proc/self/fd");
1444 [ + + ]: 879 : if (!dir) {
1445 [ # # ]: 0 : DEBUG_PRINT("Failed to open /proc/self/fd (%d)\n", errno);
1446 : 0 : return;
1447 : : }
1448 : :
1449 [ + + + + ]: 10109 : while ((d = readdir(dir)) != NULL) {
1450 [ + + + - : 10109 : if (d->d_type != DT_LNK) {
+ + ]
1451 : 1758 : continue;
1452 : : }
1453 : :
1454 [ + - ]: 8351 : snprintf(proc_fd_path, sizeof(proc_fd_path), "/proc/self/fd/%s", d->d_name);
1455 [ + + + - : 8351 : if (readlink(proc_fd_path, link_path, sizeof(link_path)) != (sizeof(vfio_path) - 1)) {
+ + ]
1456 : 6591 : continue;
1457 : : }
1458 : :
1459 [ + + + - : 1760 : if (memcmp(link_path, vfio_path, sizeof(vfio_path) - 1) == 0) {
+ + ]
1460 [ - + ]: 879 : sscanf(d->d_name, "%d", &g_vfio.fd);
1461 : 879 : break;
1462 : : }
1463 : : }
1464 : :
1465 [ + + ]: 879 : closedir(dir);
1466 : :
1467 [ + + ]: 879 : if (g_vfio.fd < 0) {
1468 : 0 : DEBUG_PRINT("Failed to discover DPDK VFIO container fd.\n");
1469 : 0 : return;
1470 : : }
1471 : :
1472 [ + - ]: 879 : g_vfio.enabled = true;
1473 : :
1474 : 879 : return;
1475 : 66 : }
1476 : :
1477 : : #endif
1478 : :
1479 : : void
1480 : 1830 : vtophys_pci_device_added(struct rte_pci_device *pci_device)
1481 : : {
1482 : : struct spdk_vtophys_pci_device *vtophys_dev;
1483 : :
1484 [ + - ]: 1830 : pthread_mutex_lock(&g_vtophys_pci_devices_mutex);
1485 : :
1486 : 1830 : vtophys_dev = calloc(1, sizeof(*vtophys_dev));
1487 [ + - ]: 1830 : if (vtophys_dev) {
1488 [ + - + - ]: 1830 : vtophys_dev->pci_device = pci_device;
1489 [ + - + - : 1830 : TAILQ_INSERT_TAIL(&g_vtophys_pci_devices, vtophys_dev, tailq);
+ - + - +
- + - + -
+ - + - +
- + - +
- ]
1490 : 2 : } else {
1491 : 0 : DEBUG_PRINT("Memory allocation error\n");
1492 : : }
1493 [ + - ]: 1830 : pthread_mutex_unlock(&g_vtophys_pci_devices_mutex);
1494 : :
1495 : : #if VFIO_ENABLED
1496 : : struct spdk_vfio_dma_map *dma_map;
1497 : : int ret;
1498 : :
1499 [ + + + + : 1830 : if (!g_vfio.enabled) {
+ - ]
1500 : 783 : return;
1501 : : }
1502 : :
1503 [ + - ]: 1047 : pthread_mutex_lock(&g_vfio.mutex);
1504 : 1047 : g_vfio.device_ref++;
1505 [ + + - + ]: 1047 : if (g_vfio.device_ref > 1) {
1506 [ # # ]: 886 : pthread_mutex_unlock(&g_vfio.mutex);
1507 : 886 : return;
1508 : : }
1509 : :
1510 : : /* This is the first SPDK device using DPDK vfio. This means that the first
1511 : : * IOMMU group might have been just been added to the DPDK vfio container.
1512 : : * From this point it is certain that the memory can be mapped now.
1513 : : */
1514 [ + + + - : 708 : TAILQ_FOREACH(dma_map, &g_vfio.maps, tailq) {
+ + + - +
- + - ]
1515 [ + - - + : 556 : ret = ioctl(g_vfio.fd, VFIO_IOMMU_MAP_DMA, &dma_map->map);
+ - - + +
- - + + -
+ - ]
1516 [ + + ]: 556 : if (ret) {
1517 [ # # ]: 9 : DEBUG_PRINT("Cannot update DMA mapping, error %d\n", errno);
1518 : 9 : break;
1519 : : }
1520 : 2 : }
1521 [ + - ]: 161 : pthread_mutex_unlock(&g_vfio.mutex);
1522 : : #endif
1523 : 2 : }
1524 : :
1525 : : void
1526 : 1094 : vtophys_pci_device_removed(struct rte_pci_device *pci_device)
1527 : : {
1528 : : struct spdk_vtophys_pci_device *vtophys_dev;
1529 : :
1530 [ + - ]: 1094 : pthread_mutex_lock(&g_vtophys_pci_devices_mutex);
1531 [ + + # # : 1179 : TAILQ_FOREACH(vtophys_dev, &g_vtophys_pci_devices, tailq) {
# # # # ]
1532 [ + + + - : 1179 : if (vtophys_dev->pci_device == pci_device) {
- + ]
1533 [ + + + - : 1094 : TAILQ_REMOVE(&g_vtophys_pci_devices, vtophys_dev, tailq);
+ - - + #
# # # # #
# # # # #
# # # # #
# # + - +
- + - + -
+ - + - +
- + - + -
+ - + - ]
1534 : 1094 : free(vtophys_dev);
1535 : 1094 : break;
1536 : : }
1537 : 0 : }
1538 [ + - ]: 1094 : pthread_mutex_unlock(&g_vtophys_pci_devices_mutex);
1539 : :
1540 : : #if VFIO_ENABLED
1541 : : struct spdk_vfio_dma_map *dma_map;
1542 : : int ret;
1543 : :
1544 [ + + + + : 1094 : if (!g_vfio.enabled) {
+ - ]
1545 : 570 : return;
1546 : : }
1547 : :
1548 [ + - ]: 524 : pthread_mutex_lock(&g_vfio.mutex);
1549 [ + + + - : 524 : assert(g_vfio.device_ref > 0);
# # ]
1550 : 524 : g_vfio.device_ref--;
1551 [ + + - + ]: 524 : if (g_vfio.device_ref > 0) {
1552 [ # # ]: 400 : pthread_mutex_unlock(&g_vfio.mutex);
1553 : 400 : return;
1554 : : }
1555 : :
1556 : : /* This is the last SPDK device using DPDK vfio. If DPDK doesn't have
1557 : : * any additional devices using it's vfio container, all the mappings
1558 : : * will be automatically removed by the Linux vfio driver. We unmap
1559 : : * the memory manually to be able to easily re-map it later regardless
1560 : : * of other, external factors.
1561 : : */
1562 [ + + + - : 124 : TAILQ_FOREACH(dma_map, &g_vfio.maps, tailq) {
+ - # # #
# # # ]
1563 : 11 : struct vfio_iommu_type1_dma_unmap unmap = {};
1564 : 11 : unmap.argsz = sizeof(unmap);
1565 [ # # ]: 11 : unmap.flags = 0;
1566 [ # # # # : 11 : unmap.iova = dma_map->map.iova;
# # # # ]
1567 [ # # # # : 11 : unmap.size = dma_map->map.size;
# # # # ]
1568 [ # # # # : 11 : ret = ioctl(g_vfio.fd, VFIO_IOMMU_UNMAP_DMA, &unmap);
# # # # #
# # # #
# ]
1569 [ + - ]: 11 : if (ret) {
1570 [ # # ]: 11 : DEBUG_PRINT("Cannot unmap DMA memory, error %d\n", errno);
1571 : 11 : break;
1572 : : }
1573 : 0 : }
1574 [ + - ]: 124 : pthread_mutex_unlock(&g_vfio.mutex);
1575 : : #endif
1576 : 2 : }
1577 : :
1578 : : int
1579 : 2710 : vtophys_init(void)
1580 : : {
1581 : 2710 : const struct spdk_mem_map_ops vtophys_map_ops = {
1582 : : .notify_cb = vtophys_notify,
1583 : : .are_contiguous = vtophys_check_contiguous_entries,
1584 : : };
1585 : :
1586 : 2710 : const struct spdk_mem_map_ops phys_ref_map_ops = {
1587 : : .notify_cb = NULL,
1588 : : .are_contiguous = NULL,
1589 : : };
1590 : :
1591 : 2710 : const struct spdk_mem_map_ops numa_map_ops = {
1592 : : .notify_cb = numa_notify,
1593 : : .are_contiguous = NULL,
1594 : : };
1595 : :
1596 : : #if VFIO_ENABLED
1597 : 2710 : vtophys_iommu_init();
1598 : : #endif
1599 : :
1600 : 2710 : g_phys_ref_map = spdk_mem_map_alloc(0, &phys_ref_map_ops, NULL);
1601 [ + + ]: 2710 : if (g_phys_ref_map == NULL) {
1602 : 0 : DEBUG_PRINT("phys_ref map allocation failed.\n");
1603 : 0 : return -ENOMEM;
1604 : : }
1605 : :
1606 : 2710 : g_numa_map = spdk_mem_map_alloc(SPDK_ENV_NUMA_ID_ANY, &numa_map_ops, NULL);
1607 [ + + ]: 2710 : if (g_numa_map == NULL) {
1608 : 0 : DEBUG_PRINT("numa map allocation failed.\n");
1609 : 0 : spdk_mem_map_free(&g_phys_ref_map);
1610 : 0 : return -ENOMEM;
1611 : : }
1612 : :
1613 [ + + + + ]: 2710 : if (g_huge_pages) {
1614 : 2702 : g_vtophys_map = spdk_mem_map_alloc(SPDK_VTOPHYS_ERROR, &vtophys_map_ops, NULL);
1615 [ + + ]: 2702 : if (g_vtophys_map == NULL) {
1616 : 0 : DEBUG_PRINT("vtophys map allocation failed\n");
1617 : 0 : spdk_mem_map_free(&g_numa_map);
1618 : 0 : spdk_mem_map_free(&g_phys_ref_map);
1619 : 0 : return -ENOMEM;
1620 : : }
1621 : 66 : }
1622 : 2710 : return 0;
1623 : 66 : }
1624 : :
1625 : : void
1626 : 2651 : vtophys_fini(void)
1627 : : {
1628 : 2651 : spdk_mem_map_free(&g_vtophys_map);
1629 : 2651 : spdk_mem_map_free(&g_numa_map);
1630 : 2651 : spdk_mem_map_free(&g_phys_ref_map);
1631 : 2651 : }
1632 : :
1633 : : uint64_t
1634 : 123689782 : spdk_vtophys(const void *buf, uint64_t *size)
1635 : : {
1636 : : uint64_t vaddr, paddr_2mb;
1637 : :
1638 [ + + + + ]: 123689782 : if (!g_huge_pages) {
1639 : 0 : return SPDK_VTOPHYS_ERROR;
1640 : : }
1641 : :
1642 : 123689782 : vaddr = (uint64_t)buf;
1643 : 123689782 : paddr_2mb = spdk_mem_map_translate(g_vtophys_map, vaddr, size);
1644 : :
1645 : : /*
1646 : : * SPDK_VTOPHYS_ERROR has all bits set, so if the lookup returned SPDK_VTOPHYS_ERROR,
1647 : : * we will still bitwise-or it with the buf offset below, but the result will still be
1648 : : * SPDK_VTOPHYS_ERROR. However now that we do + rather than | (due to PCI vtophys being
1649 : : * unaligned) we must now check the return value before addition.
1650 : : */
1651 : : SPDK_STATIC_ASSERT(SPDK_VTOPHYS_ERROR == UINT64_C(-1), "SPDK_VTOPHYS_ERROR should be all 1s");
1652 [ + + ]: 123689782 : if (paddr_2mb == SPDK_VTOPHYS_ERROR) {
1653 : 672 : return SPDK_VTOPHYS_ERROR;
1654 : : } else {
1655 [ - + ]: 123689110 : return paddr_2mb + (vaddr & MASK_2MB);
1656 : : }
1657 : 2452 : }
1658 : :
1659 : : int32_t
1660 : 0 : spdk_mem_get_numa_id(const void *buf, uint64_t *size)
1661 : : {
1662 : 0 : return spdk_mem_map_translate(g_numa_map, (uint64_t)buf, size);
1663 : : }
1664 : :
1665 : : int
1666 : 920 : spdk_mem_get_fd_and_offset(void *vaddr, uint64_t *offset)
1667 : : {
1668 : : struct rte_memseg *seg;
1669 : : int ret, fd;
1670 : :
1671 : 920 : seg = rte_mem_virt2memseg(vaddr, NULL);
1672 [ + + ]: 920 : if (!seg) {
1673 : 0 : SPDK_ERRLOG("memory %p doesn't exist\n", vaddr);
1674 : 0 : return -ENOENT;
1675 : : }
1676 : :
1677 : 920 : fd = rte_memseg_get_fd_thread_unsafe(seg);
1678 [ + + ]: 920 : if (fd < 0) {
1679 : 0 : return fd;
1680 : : }
1681 : :
1682 : 920 : ret = rte_memseg_get_fd_offset_thread_unsafe(seg, offset);
1683 [ - + ]: 920 : if (ret < 0) {
1684 : 0 : return ret;
1685 : : }
1686 : :
1687 : 920 : return fd;
1688 : 864 : }
1689 : :
1690 : : void
1691 : 8 : mem_disable_huge_pages(void)
1692 : : {
1693 : 8 : g_huge_pages = false;
1694 : 8 : mem_map_use_page_shift(SHIFT_4KB);
1695 : 8 : }
1696 : :
1697 : : void
1698 : 50 : mem_map_use_page_shift(uint32_t page_shift)
1699 : : {
1700 : 50 : g_map_page_cfg.shift = page_shift;
1701 [ + + + - ]: 50 : g_map_page_cfg.size = 1UL << page_shift;
1702 [ + - + - ]: 50 : g_map_page_cfg.mask = g_map_page_cfg.size - 1;
1703 [ + + + - ]: 50 : g_map_page_cfg.num_pages_per_gb = 1UL << (SHIFT_1GB - page_shift);
1704 : 50 : }
|