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