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