1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (C) 2012-2014 Matteo Landi 5 * Copyright (C) 2012-2016 Luigi Rizzo 6 * Copyright (C) 2012-2016 Giuseppe Lettieri 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #ifdef linux 32 #include "bsd_glue.h" 33 #endif /* linux */ 34 35 #ifdef __APPLE__ 36 #include "osx_glue.h" 37 #endif /* __APPLE__ */ 38 39 #ifdef __FreeBSD__ 40 #include <sys/cdefs.h> /* prerequisite */ 41 #include <sys/types.h> 42 #include <sys/malloc.h> 43 #include <sys/kernel.h> /* MALLOC_DEFINE */ 44 #include <sys/proc.h> 45 #include <vm/vm.h> /* vtophys */ 46 #include <vm/pmap.h> /* vtophys */ 47 #include <sys/socket.h> /* sockaddrs */ 48 #include <sys/selinfo.h> 49 #include <sys/sysctl.h> 50 #include <net/if.h> 51 #include <net/if_var.h> 52 #include <net/vnet.h> 53 #include <machine/bus.h> /* bus_dmamap_* */ 54 55 /* M_NETMAP only used in here */ 56 MALLOC_DECLARE(M_NETMAP); 57 MALLOC_DEFINE(M_NETMAP, "netmap", "Network memory map"); 58 59 #endif /* __FreeBSD__ */ 60 61 #ifdef _WIN32 62 #include <win_glue.h> 63 #endif 64 65 #include <net/netmap.h> 66 #include <dev/netmap/netmap_kern.h> 67 #include <net/netmap_virt.h> 68 #include "netmap_mem2.h" 69 70 #ifdef _WIN32_USE_SMALL_GENERIC_DEVICES_MEMORY 71 #define NETMAP_BUF_MAX_NUM 8*4096 /* if too big takes too much time to allocate */ 72 #else 73 #define NETMAP_BUF_MAX_NUM 20*4096*2 /* large machine */ 74 #endif 75 76 #define NETMAP_POOL_MAX_NAMSZ 32 77 78 79 enum { 80 NETMAP_IF_POOL = 0, 81 NETMAP_RING_POOL, 82 NETMAP_BUF_POOL, 83 NETMAP_POOLS_NR 84 }; 85 86 87 struct netmap_obj_params { 88 u_int size; 89 u_int num; 90 91 u_int last_size; 92 u_int last_num; 93 }; 94 95 struct netmap_obj_pool { 96 char name[NETMAP_POOL_MAX_NAMSZ]; /* name of the allocator */ 97 98 /* ---------------------------------------------------*/ 99 /* these are only meaningful if the pool is finalized */ 100 /* (see 'finalized' field in netmap_mem_d) */ 101 size_t memtotal; /* actual total memory space */ 102 103 struct lut_entry *lut; /* virt,phys addresses, objtotal entries */ 104 uint32_t *bitmap; /* one bit per buffer, 1 means free */ 105 uint32_t *invalid_bitmap;/* one bit per buffer, 1 means invalid */ 106 uint32_t bitmap_slots; /* number of uint32 entries in bitmap */ 107 108 u_int objtotal; /* actual total number of objects. */ 109 u_int numclusters; /* actual number of clusters */ 110 u_int objfree; /* number of free objects. */ 111 112 int alloc_done; /* we have allocated the memory */ 113 /* ---------------------------------------------------*/ 114 115 /* limits */ 116 u_int objminsize; /* minimum object size */ 117 u_int objmaxsize; /* maximum object size */ 118 u_int nummin; /* minimum number of objects */ 119 u_int nummax; /* maximum number of objects */ 120 121 /* these are changed only by config */ 122 u_int _objtotal; /* total number of objects */ 123 u_int _objsize; /* object size */ 124 u_int _clustsize; /* cluster size */ 125 u_int _clustentries; /* objects per cluster */ 126 u_int _numclusters; /* number of clusters */ 127 128 /* requested values */ 129 u_int r_objtotal; 130 u_int r_objsize; 131 }; 132 133 #define NMA_LOCK_T NM_MTX_T 134 #define NMA_LOCK_INIT(n) NM_MTX_INIT((n)->nm_mtx) 135 #define NMA_LOCK_DESTROY(n) NM_MTX_DESTROY((n)->nm_mtx) 136 #define NMA_LOCK(n) NM_MTX_LOCK((n)->nm_mtx) 137 #define NMA_SPINLOCK(n) NM_MTX_SPINLOCK((n)->nm_mtx) 138 #define NMA_UNLOCK(n) NM_MTX_UNLOCK((n)->nm_mtx) 139 140 struct netmap_mem_ops { 141 int (*nmd_get_lut)(struct netmap_mem_d *, struct netmap_lut*); 142 int (*nmd_get_info)(struct netmap_mem_d *, uint64_t *size, 143 u_int *memflags, uint16_t *id); 144 145 vm_paddr_t (*nmd_ofstophys)(struct netmap_mem_d *, vm_ooffset_t); 146 int (*nmd_config)(struct netmap_mem_d *); 147 int (*nmd_finalize)(struct netmap_mem_d *, struct netmap_adapter *); 148 void (*nmd_deref)(struct netmap_mem_d *, struct netmap_adapter *); 149 ssize_t (*nmd_if_offset)(struct netmap_mem_d *, const void *vaddr); 150 void (*nmd_delete)(struct netmap_mem_d *); 151 152 struct netmap_if * (*nmd_if_new)(struct netmap_mem_d *, 153 struct netmap_adapter *, struct netmap_priv_d *); 154 void (*nmd_if_delete)(struct netmap_mem_d *, 155 struct netmap_adapter *, struct netmap_if *); 156 int (*nmd_rings_create)(struct netmap_mem_d *, 157 struct netmap_adapter *); 158 void (*nmd_rings_delete)(struct netmap_mem_d *, 159 struct netmap_adapter *); 160 }; 161 162 struct netmap_mem_d { 163 NMA_LOCK_T nm_mtx; /* protect the allocator */ 164 size_t nm_totalsize; /* shorthand */ 165 166 u_int flags; 167 #define NETMAP_MEM_FINALIZED 0x1 /* preallocation done */ 168 #define NETMAP_MEM_HIDDEN 0x8 /* being prepared */ 169 #define NETMAP_MEM_NOMAP 0x10 /* do not map/unmap pdevs */ 170 int lasterr; /* last error for curr config */ 171 int active; /* active users */ 172 int refcount; 173 /* the three allocators */ 174 struct netmap_obj_pool pools[NETMAP_POOLS_NR]; 175 176 nm_memid_t nm_id; /* allocator identifier */ 177 int nm_grp; /* iommu group id */ 178 179 /* list of all existing allocators, sorted by nm_id */ 180 struct netmap_mem_d *prev, *next; 181 182 const struct netmap_mem_ops *ops; 183 184 struct netmap_obj_params params[NETMAP_POOLS_NR]; 185 186 #define NM_MEM_NAMESZ 16 187 char name[NM_MEM_NAMESZ]; 188 }; 189 190 int 191 netmap_mem_get_lut(struct netmap_mem_d *nmd, struct netmap_lut *lut) 192 { 193 int rv; 194 195 NMA_LOCK(nmd); 196 rv = nmd->ops->nmd_get_lut(nmd, lut); 197 NMA_UNLOCK(nmd); 198 199 return rv; 200 } 201 202 int 203 netmap_mem_get_info(struct netmap_mem_d *nmd, uint64_t *size, 204 u_int *memflags, nm_memid_t *memid) 205 { 206 int rv; 207 208 NMA_LOCK(nmd); 209 rv = nmd->ops->nmd_get_info(nmd, size, memflags, memid); 210 NMA_UNLOCK(nmd); 211 212 return rv; 213 } 214 215 vm_paddr_t 216 netmap_mem_ofstophys(struct netmap_mem_d *nmd, vm_ooffset_t off) 217 { 218 vm_paddr_t pa; 219 220 #if defined(__FreeBSD__) 221 /* This function is called by netmap_dev_pager_fault(), which holds a 222 * non-sleepable lock since FreeBSD 12. Since we cannot sleep, we 223 * spin on the trylock. */ 224 NMA_SPINLOCK(nmd); 225 #else 226 NMA_LOCK(nmd); 227 #endif 228 pa = nmd->ops->nmd_ofstophys(nmd, off); 229 NMA_UNLOCK(nmd); 230 231 return pa; 232 } 233 234 static int 235 netmap_mem_config(struct netmap_mem_d *nmd) 236 { 237 if (nmd->active) { 238 /* already in use. Not fatal, but we 239 * cannot change the configuration 240 */ 241 return 0; 242 } 243 244 return nmd->ops->nmd_config(nmd); 245 } 246 247 ssize_t 248 netmap_mem_if_offset(struct netmap_mem_d *nmd, const void *off) 249 { 250 ssize_t rv; 251 252 NMA_LOCK(nmd); 253 rv = nmd->ops->nmd_if_offset(nmd, off); 254 NMA_UNLOCK(nmd); 255 256 return rv; 257 } 258 259 static void 260 netmap_mem_delete(struct netmap_mem_d *nmd) 261 { 262 nmd->ops->nmd_delete(nmd); 263 } 264 265 struct netmap_if * 266 netmap_mem_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv) 267 { 268 struct netmap_if *nifp; 269 struct netmap_mem_d *nmd = na->nm_mem; 270 271 NMA_LOCK(nmd); 272 nifp = nmd->ops->nmd_if_new(nmd, na, priv); 273 NMA_UNLOCK(nmd); 274 275 return nifp; 276 } 277 278 void 279 netmap_mem_if_delete(struct netmap_adapter *na, struct netmap_if *nif) 280 { 281 struct netmap_mem_d *nmd = na->nm_mem; 282 283 NMA_LOCK(nmd); 284 nmd->ops->nmd_if_delete(nmd, na, nif); 285 NMA_UNLOCK(nmd); 286 } 287 288 int 289 netmap_mem_rings_create(struct netmap_adapter *na) 290 { 291 int rv; 292 struct netmap_mem_d *nmd = na->nm_mem; 293 294 NMA_LOCK(nmd); 295 rv = nmd->ops->nmd_rings_create(nmd, na); 296 NMA_UNLOCK(nmd); 297 298 return rv; 299 } 300 301 void 302 netmap_mem_rings_delete(struct netmap_adapter *na) 303 { 304 struct netmap_mem_d *nmd = na->nm_mem; 305 306 NMA_LOCK(nmd); 307 nmd->ops->nmd_rings_delete(nmd, na); 308 NMA_UNLOCK(nmd); 309 } 310 311 static int netmap_mem_map(struct netmap_obj_pool *, struct netmap_adapter *); 312 static int netmap_mem_unmap(struct netmap_obj_pool *, struct netmap_adapter *); 313 static int nm_mem_check_group(struct netmap_mem_d *, bus_dma_tag_t); 314 static void nm_mem_release_id(struct netmap_mem_d *); 315 316 nm_memid_t 317 netmap_mem_get_id(struct netmap_mem_d *nmd) 318 { 319 return nmd->nm_id; 320 } 321 322 #ifdef NM_DEBUG_MEM_PUTGET 323 #define NM_DBG_REFC(nmd, func, line) \ 324 nm_prinf("%s:%d mem[%d:%d] -> %d", func, line, (nmd)->nm_id, (nmd)->nm_grp, (nmd)->refcount); 325 #else 326 #define NM_DBG_REFC(nmd, func, line) 327 #endif 328 329 /* circular list of all existing allocators */ 330 static struct netmap_mem_d *netmap_last_mem_d = &nm_mem; 331 static NM_MTX_T nm_mem_list_lock; 332 333 struct netmap_mem_d * 334 __netmap_mem_get(struct netmap_mem_d *nmd, const char *func, int line) 335 { 336 NM_MTX_LOCK(nm_mem_list_lock); 337 nmd->refcount++; 338 NM_DBG_REFC(nmd, func, line); 339 NM_MTX_UNLOCK(nm_mem_list_lock); 340 return nmd; 341 } 342 343 void 344 __netmap_mem_put(struct netmap_mem_d *nmd, const char *func, int line) 345 { 346 int last; 347 NM_MTX_LOCK(nm_mem_list_lock); 348 last = (--nmd->refcount == 0); 349 if (last) 350 nm_mem_release_id(nmd); 351 NM_DBG_REFC(nmd, func, line); 352 NM_MTX_UNLOCK(nm_mem_list_lock); 353 if (last) 354 netmap_mem_delete(nmd); 355 } 356 357 int 358 netmap_mem_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na) 359 { 360 int lasterr = 0; 361 if (nm_mem_check_group(nmd, na->pdev) < 0) { 362 return ENOMEM; 363 } 364 365 NMA_LOCK(nmd); 366 367 if (netmap_mem_config(nmd)) 368 goto out; 369 370 nmd->active++; 371 372 nmd->lasterr = nmd->ops->nmd_finalize(nmd, na); 373 374 if (!nmd->lasterr && !(nmd->flags & NETMAP_MEM_NOMAP)) { 375 nmd->lasterr = netmap_mem_map(&nmd->pools[NETMAP_BUF_POOL], na); 376 } 377 378 out: 379 lasterr = nmd->lasterr; 380 NMA_UNLOCK(nmd); 381 382 if (lasterr) 383 netmap_mem_deref(nmd, na); 384 385 return lasterr; 386 } 387 388 static int 389 nm_isset(uint32_t *bitmap, u_int i) 390 { 391 return bitmap[ (i>>5) ] & ( 1U << (i & 31U) ); 392 } 393 394 395 static int 396 netmap_init_obj_allocator_bitmap(struct netmap_obj_pool *p) 397 { 398 u_int n, j; 399 400 if (p->bitmap == NULL) { 401 /* Allocate the bitmap */ 402 n = (p->objtotal + 31) / 32; 403 p->bitmap = nm_os_malloc(sizeof(p->bitmap[0]) * n); 404 if (p->bitmap == NULL) { 405 nm_prerr("Unable to create bitmap (%d entries) for allocator '%s'", (int)n, 406 p->name); 407 return ENOMEM; 408 } 409 p->bitmap_slots = n; 410 } else { 411 memset(p->bitmap, 0, p->bitmap_slots * sizeof(p->bitmap[0])); 412 } 413 414 p->objfree = 0; 415 /* 416 * Set all the bits in the bitmap that have 417 * corresponding buffers to 1 to indicate they are 418 * free. 419 */ 420 for (j = 0; j < p->objtotal; j++) { 421 if (p->invalid_bitmap && nm_isset(p->invalid_bitmap, j)) { 422 if (netmap_debug & NM_DEBUG_MEM) 423 nm_prinf("skipping %s %d", p->name, j); 424 continue; 425 } 426 p->bitmap[ (j>>5) ] |= ( 1U << (j & 31U) ); 427 p->objfree++; 428 } 429 430 if (netmap_verbose) 431 nm_prinf("%s free %u", p->name, p->objfree); 432 if (p->objfree == 0) { 433 if (netmap_verbose) 434 nm_prerr("%s: no objects available", p->name); 435 return ENOMEM; 436 } 437 438 return 0; 439 } 440 441 static int 442 netmap_mem_init_bitmaps(struct netmap_mem_d *nmd) 443 { 444 int i, error = 0; 445 446 for (i = 0; i < NETMAP_POOLS_NR; i++) { 447 struct netmap_obj_pool *p = &nmd->pools[i]; 448 449 error = netmap_init_obj_allocator_bitmap(p); 450 if (error) 451 return error; 452 } 453 454 /* 455 * buffers 0 and 1 are reserved 456 */ 457 if (nmd->pools[NETMAP_BUF_POOL].objfree < 2) { 458 nm_prerr("%s: not enough buffers", nmd->pools[NETMAP_BUF_POOL].name); 459 return ENOMEM; 460 } 461 462 nmd->pools[NETMAP_BUF_POOL].objfree -= 2; 463 if (nmd->pools[NETMAP_BUF_POOL].bitmap) { 464 /* XXX This check is a workaround that prevents a 465 * NULL pointer crash which currently happens only 466 * with ptnetmap guests. 467 * Removed shared-info --> is the bug still there? */ 468 nmd->pools[NETMAP_BUF_POOL].bitmap[0] = ~3U; 469 } 470 return 0; 471 } 472 473 int 474 netmap_mem_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na) 475 { 476 int last_user = 0; 477 NMA_LOCK(nmd); 478 if (na->active_fds <= 0 && !(nmd->flags & NETMAP_MEM_NOMAP)) 479 netmap_mem_unmap(&nmd->pools[NETMAP_BUF_POOL], na); 480 if (nmd->active == 1) { 481 last_user = 1; 482 /* 483 * Reset the allocator when it falls out of use so that any 484 * pool resources leaked by unclean application exits are 485 * reclaimed. 486 */ 487 netmap_mem_init_bitmaps(nmd); 488 } 489 nmd->ops->nmd_deref(nmd, na); 490 491 nmd->active--; 492 if (last_user) { 493 nmd->lasterr = 0; 494 } 495 496 NMA_UNLOCK(nmd); 497 return last_user; 498 } 499 500 501 /* accessor functions */ 502 static int 503 netmap_mem2_get_lut(struct netmap_mem_d *nmd, struct netmap_lut *lut) 504 { 505 lut->lut = nmd->pools[NETMAP_BUF_POOL].lut; 506 #ifdef __FreeBSD__ 507 lut->plut = lut->lut; 508 #endif 509 lut->objtotal = nmd->pools[NETMAP_BUF_POOL].objtotal; 510 lut->objsize = nmd->pools[NETMAP_BUF_POOL]._objsize; 511 512 return 0; 513 } 514 515 static struct netmap_obj_params netmap_min_priv_params[NETMAP_POOLS_NR] = { 516 [NETMAP_IF_POOL] = { 517 .size = 1024, 518 .num = 2, 519 }, 520 [NETMAP_RING_POOL] = { 521 .size = 5*PAGE_SIZE, 522 .num = 4, 523 }, 524 [NETMAP_BUF_POOL] = { 525 .size = 2048, 526 .num = 4098, 527 }, 528 }; 529 530 531 /* 532 * nm_mem is the memory allocator used for all physical interfaces 533 * running in netmap mode. 534 * Virtual (VALE) ports will have each its own allocator. 535 */ 536 extern const struct netmap_mem_ops netmap_mem_global_ops; /* forward */ 537 struct netmap_mem_d nm_mem = { /* Our memory allocator. */ 538 .pools = { 539 [NETMAP_IF_POOL] = { 540 .name = "netmap_if", 541 .objminsize = sizeof(struct netmap_if), 542 .objmaxsize = 4096, 543 .nummin = 10, /* don't be stingy */ 544 .nummax = 10000, /* XXX very large */ 545 }, 546 [NETMAP_RING_POOL] = { 547 .name = "netmap_ring", 548 .objminsize = sizeof(struct netmap_ring), 549 .objmaxsize = 32*PAGE_SIZE, 550 .nummin = 2, 551 .nummax = 1024, 552 }, 553 [NETMAP_BUF_POOL] = { 554 .name = "netmap_buf", 555 .objminsize = 64, 556 .objmaxsize = 65536, 557 .nummin = 4, 558 .nummax = 1000000, /* one million! */ 559 }, 560 }, 561 562 .params = { 563 [NETMAP_IF_POOL] = { 564 .size = 1024, 565 .num = 100, 566 }, 567 [NETMAP_RING_POOL] = { 568 .size = 9*PAGE_SIZE, 569 .num = 200, 570 }, 571 [NETMAP_BUF_POOL] = { 572 .size = 2048, 573 .num = NETMAP_BUF_MAX_NUM, 574 }, 575 }, 576 577 .nm_id = 1, 578 .nm_grp = -1, 579 580 .prev = &nm_mem, 581 .next = &nm_mem, 582 583 .ops = &netmap_mem_global_ops, 584 585 .name = "1" 586 }; 587 588 static struct netmap_mem_d nm_mem_blueprint; 589 590 /* blueprint for the private memory allocators */ 591 /* XXX clang is not happy about using name as a print format */ 592 static const struct netmap_mem_d nm_blueprint = { 593 .pools = { 594 [NETMAP_IF_POOL] = { 595 .name = "%s_if", 596 .objminsize = sizeof(struct netmap_if), 597 .objmaxsize = 4096, 598 .nummin = 1, 599 .nummax = 100, 600 }, 601 [NETMAP_RING_POOL] = { 602 .name = "%s_ring", 603 .objminsize = sizeof(struct netmap_ring), 604 .objmaxsize = 32*PAGE_SIZE, 605 .nummin = 2, 606 .nummax = 1024, 607 }, 608 [NETMAP_BUF_POOL] = { 609 .name = "%s_buf", 610 .objminsize = 64, 611 .objmaxsize = 65536, 612 .nummin = 4, 613 .nummax = 1000000, /* one million! */ 614 }, 615 }, 616 617 .nm_grp = -1, 618 619 .flags = NETMAP_MEM_PRIVATE, 620 621 .ops = &netmap_mem_global_ops, 622 }; 623 624 /* memory allocator related sysctls */ 625 626 #define STRINGIFY(x) #x 627 628 629 #define DECLARE_SYSCTLS(id, name) \ 630 SYSBEGIN(mem2_ ## name); \ 631 SYSCTL_INT(_dev_netmap, OID_AUTO, name##_size, \ 632 CTLFLAG_RW, &nm_mem.params[id].size, 0, "Requested size of netmap " STRINGIFY(name) "s"); \ 633 SYSCTL_INT(_dev_netmap, OID_AUTO, name##_curr_size, \ 634 CTLFLAG_RD, &nm_mem.pools[id]._objsize, 0, "Current size of netmap " STRINGIFY(name) "s"); \ 635 SYSCTL_INT(_dev_netmap, OID_AUTO, name##_num, \ 636 CTLFLAG_RW, &nm_mem.params[id].num, 0, "Requested number of netmap " STRINGIFY(name) "s"); \ 637 SYSCTL_INT(_dev_netmap, OID_AUTO, name##_curr_num, \ 638 CTLFLAG_RD, &nm_mem.pools[id].objtotal, 0, "Current number of netmap " STRINGIFY(name) "s"); \ 639 SYSCTL_INT(_dev_netmap, OID_AUTO, priv_##name##_size, \ 640 CTLFLAG_RW, &netmap_min_priv_params[id].size, 0, \ 641 "Default size of private netmap " STRINGIFY(name) "s"); \ 642 SYSCTL_INT(_dev_netmap, OID_AUTO, priv_##name##_num, \ 643 CTLFLAG_RW, &netmap_min_priv_params[id].num, 0, \ 644 "Default number of private netmap " STRINGIFY(name) "s"); \ 645 SYSEND 646 647 SYSCTL_DECL(_dev_netmap); 648 DECLARE_SYSCTLS(NETMAP_IF_POOL, if); 649 DECLARE_SYSCTLS(NETMAP_RING_POOL, ring); 650 DECLARE_SYSCTLS(NETMAP_BUF_POOL, buf); 651 652 /* call with nm_mem_list_lock held */ 653 static int 654 nm_mem_assign_id_locked(struct netmap_mem_d *nmd, int grp_id) 655 { 656 nm_memid_t id; 657 struct netmap_mem_d *scan = netmap_last_mem_d; 658 int error = ENOMEM; 659 660 do { 661 /* we rely on unsigned wrap around */ 662 id = scan->nm_id + 1; 663 if (id == 0) /* reserve 0 as error value */ 664 id = 1; 665 scan = scan->next; 666 if (id != scan->nm_id) { 667 nmd->nm_id = id; 668 nmd->nm_grp = grp_id; 669 nmd->prev = scan->prev; 670 nmd->next = scan; 671 scan->prev->next = nmd; 672 scan->prev = nmd; 673 netmap_last_mem_d = nmd; 674 nmd->refcount = 1; 675 NM_DBG_REFC(nmd, __FUNCTION__, __LINE__); 676 error = 0; 677 break; 678 } 679 } while (scan != netmap_last_mem_d); 680 681 return error; 682 } 683 684 /* call with nm_mem_list_lock *not* held */ 685 static int 686 nm_mem_assign_id(struct netmap_mem_d *nmd, int grp_id) 687 { 688 int ret; 689 690 NM_MTX_LOCK(nm_mem_list_lock); 691 ret = nm_mem_assign_id_locked(nmd, grp_id); 692 NM_MTX_UNLOCK(nm_mem_list_lock); 693 694 return ret; 695 } 696 697 /* call with nm_mem_list_lock held */ 698 static void 699 nm_mem_release_id(struct netmap_mem_d *nmd) 700 { 701 nmd->prev->next = nmd->next; 702 nmd->next->prev = nmd->prev; 703 704 if (netmap_last_mem_d == nmd) 705 netmap_last_mem_d = nmd->prev; 706 707 nmd->prev = nmd->next = NULL; 708 } 709 710 struct netmap_mem_d * 711 netmap_mem_find(nm_memid_t id) 712 { 713 struct netmap_mem_d *nmd; 714 715 NM_MTX_LOCK(nm_mem_list_lock); 716 nmd = netmap_last_mem_d; 717 do { 718 if (!(nmd->flags & NETMAP_MEM_HIDDEN) && nmd->nm_id == id) { 719 nmd->refcount++; 720 NM_DBG_REFC(nmd, __FUNCTION__, __LINE__); 721 NM_MTX_UNLOCK(nm_mem_list_lock); 722 return nmd; 723 } 724 nmd = nmd->next; 725 } while (nmd != netmap_last_mem_d); 726 NM_MTX_UNLOCK(nm_mem_list_lock); 727 return NULL; 728 } 729 730 static int 731 nm_mem_check_group(struct netmap_mem_d *nmd, bus_dma_tag_t dev) 732 { 733 int err = 0, id; 734 735 /* Skip not hw adapters. 736 * Vale port can use particular allocator through vale-ctl -m option 737 */ 738 if (!dev) 739 return 0; 740 id = nm_iommu_group_id(dev); 741 if (netmap_debug & NM_DEBUG_MEM) 742 nm_prinf("iommu_group %d", id); 743 744 NMA_LOCK(nmd); 745 746 if (nmd->nm_grp != id) { 747 if (netmap_verbose) 748 nm_prerr("iommu group mismatch: %d vs %d", 749 nmd->nm_grp, id); 750 nmd->lasterr = err = ENOMEM; 751 } 752 753 NMA_UNLOCK(nmd); 754 return err; 755 } 756 757 static struct lut_entry * 758 nm_alloc_lut(u_int nobj) 759 { 760 size_t n = sizeof(struct lut_entry) * nobj; 761 struct lut_entry *lut; 762 #ifdef linux 763 lut = vmalloc(n); 764 #else 765 lut = nm_os_malloc(n); 766 #endif 767 return lut; 768 } 769 770 static void 771 nm_free_lut(struct lut_entry *lut, u_int objtotal) 772 { 773 bzero(lut, sizeof(struct lut_entry) * objtotal); 774 #ifdef linux 775 vfree(lut); 776 #else 777 nm_os_free(lut); 778 #endif 779 } 780 781 #if defined(linux) || defined(_WIN32) 782 static struct plut_entry * 783 nm_alloc_plut(u_int nobj) 784 { 785 size_t n = sizeof(struct plut_entry) * nobj; 786 struct plut_entry *lut; 787 lut = vmalloc(n); 788 return lut; 789 } 790 791 static void 792 nm_free_plut(struct plut_entry * lut) 793 { 794 vfree(lut); 795 } 796 #endif /* linux or _WIN32 */ 797 798 799 /* 800 * First, find the allocator that contains the requested offset, 801 * then locate the cluster through a lookup table. 802 */ 803 static vm_paddr_t 804 netmap_mem2_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset) 805 { 806 int i; 807 vm_ooffset_t o = offset; 808 vm_paddr_t pa; 809 struct netmap_obj_pool *p; 810 811 p = nmd->pools; 812 813 for (i = 0; i < NETMAP_POOLS_NR; offset -= p[i].memtotal, i++) { 814 if (offset >= p[i].memtotal) 815 continue; 816 // now lookup the cluster's address 817 #ifndef _WIN32 818 pa = vtophys(p[i].lut[offset / p[i]._objsize].vaddr) + 819 offset % p[i]._objsize; 820 #else 821 pa = vtophys(p[i].lut[offset / p[i]._objsize].vaddr); 822 pa.QuadPart += offset % p[i]._objsize; 823 #endif 824 return pa; 825 } 826 /* this is only in case of errors */ 827 nm_prerr("invalid ofs 0x%x out of 0x%zx 0x%zx 0x%zx", (u_int)o, 828 p[NETMAP_IF_POOL].memtotal, 829 p[NETMAP_IF_POOL].memtotal 830 + p[NETMAP_RING_POOL].memtotal, 831 p[NETMAP_IF_POOL].memtotal 832 + p[NETMAP_RING_POOL].memtotal 833 + p[NETMAP_BUF_POOL].memtotal); 834 #ifndef _WIN32 835 return 0; /* bad address */ 836 #else 837 vm_paddr_t res; 838 res.QuadPart = 0; 839 return res; 840 #endif 841 } 842 843 #ifdef _WIN32 844 845 /* 846 * win32_build_virtual_memory_for_userspace 847 * 848 * This function get all the object making part of the pools and maps 849 * a contiguous virtual memory space for the userspace 850 * It works this way 851 * 1 - allocate a Memory Descriptor List wide as the sum 852 * of the memory needed for the pools 853 * 2 - cycle all the objects in every pool and for every object do 854 * 855 * 2a - cycle all the objects in every pool, get the list 856 * of the physical address descriptors 857 * 2b - calculate the offset in the array of pages descriptor in the 858 * main MDL 859 * 2c - copy the descriptors of the object in the main MDL 860 * 861 * 3 - return the resulting MDL that needs to be mapped in userland 862 * 863 * In this way we will have an MDL that describes all the memory for the 864 * objects in a single object 865 */ 866 867 PMDL 868 win32_build_user_vm_map(struct netmap_mem_d* nmd) 869 { 870 u_int memflags, ofs = 0; 871 PMDL mainMdl, tempMdl; 872 uint64_t memsize; 873 int i, j; 874 875 if (netmap_mem_get_info(nmd, &memsize, &memflags, NULL)) { 876 nm_prerr("memory not finalised yet"); 877 return NULL; 878 } 879 880 mainMdl = IoAllocateMdl(NULL, memsize, FALSE, FALSE, NULL); 881 if (mainMdl == NULL) { 882 nm_prerr("failed to allocate mdl"); 883 return NULL; 884 } 885 886 NMA_LOCK(nmd); 887 for (i = 0; i < NETMAP_POOLS_NR; i++) { 888 struct netmap_obj_pool *p = &nmd->pools[i]; 889 int clsz = p->_clustsize; 890 int clobjs = p->_clustentries; /* objects per cluster */ 891 int mdl_len = sizeof(PFN_NUMBER) * BYTES_TO_PAGES(clsz); 892 PPFN_NUMBER pSrc, pDst; 893 894 /* each pool has a different cluster size so we need to reallocate */ 895 tempMdl = IoAllocateMdl(p->lut[0].vaddr, clsz, FALSE, FALSE, NULL); 896 if (tempMdl == NULL) { 897 NMA_UNLOCK(nmd); 898 nm_prerr("fail to allocate tempMdl"); 899 IoFreeMdl(mainMdl); 900 return NULL; 901 } 902 pSrc = MmGetMdlPfnArray(tempMdl); 903 /* create one entry per cluster, the lut[] has one entry per object */ 904 for (j = 0; j < p->numclusters; j++, ofs += clsz) { 905 pDst = &MmGetMdlPfnArray(mainMdl)[BYTES_TO_PAGES(ofs)]; 906 MmInitializeMdl(tempMdl, p->lut[j*clobjs].vaddr, clsz); 907 MmBuildMdlForNonPagedPool(tempMdl); /* compute physical page addresses */ 908 RtlCopyMemory(pDst, pSrc, mdl_len); /* copy the page descriptors */ 909 mainMdl->MdlFlags = tempMdl->MdlFlags; /* XXX what is in here ? */ 910 } 911 IoFreeMdl(tempMdl); 912 } 913 NMA_UNLOCK(nmd); 914 return mainMdl; 915 } 916 917 #endif /* _WIN32 */ 918 919 /* 920 * helper function for OS-specific mmap routines (currently only windows). 921 * Given an nmd and a pool index, returns the cluster size and number of clusters. 922 * Returns 0 if memory is finalised and the pool is valid, otherwise 1. 923 * It should be called under NMA_LOCK(nmd) otherwise the underlying info can change. 924 */ 925 926 int 927 netmap_mem2_get_pool_info(struct netmap_mem_d* nmd, u_int pool, u_int *clustsize, u_int *numclusters) 928 { 929 if (!nmd || !clustsize || !numclusters || pool >= NETMAP_POOLS_NR) 930 return 1; /* invalid arguments */ 931 // NMA_LOCK_ASSERT(nmd); 932 if (!(nmd->flags & NETMAP_MEM_FINALIZED)) { 933 *clustsize = *numclusters = 0; 934 return 1; /* not ready yet */ 935 } 936 *clustsize = nmd->pools[pool]._clustsize; 937 *numclusters = nmd->pools[pool].numclusters; 938 return 0; /* success */ 939 } 940 941 static int 942 netmap_mem2_get_info(struct netmap_mem_d* nmd, uint64_t* size, 943 u_int *memflags, nm_memid_t *id) 944 { 945 int error = 0; 946 error = netmap_mem_config(nmd); 947 if (error) 948 goto out; 949 if (size) { 950 if (nmd->flags & NETMAP_MEM_FINALIZED) { 951 *size = nmd->nm_totalsize; 952 } else { 953 int i; 954 *size = 0; 955 for (i = 0; i < NETMAP_POOLS_NR; i++) { 956 struct netmap_obj_pool *p = nmd->pools + i; 957 *size += ((size_t)p->_numclusters * (size_t)p->_clustsize); 958 } 959 } 960 } 961 if (memflags) 962 *memflags = nmd->flags; 963 if (id) 964 *id = nmd->nm_id; 965 out: 966 return error; 967 } 968 969 /* 970 * we store objects by kernel address, need to find the offset 971 * within the pool to export the value to userspace. 972 * Algorithm: scan until we find the cluster, then add the 973 * actual offset in the cluster 974 */ 975 static ssize_t 976 netmap_obj_offset(struct netmap_obj_pool *p, const void *vaddr) 977 { 978 int i, k = p->_clustentries, n = p->objtotal; 979 ssize_t ofs = 0; 980 981 for (i = 0; i < n; i += k, ofs += p->_clustsize) { 982 const char *base = p->lut[i].vaddr; 983 ssize_t relofs = (const char *) vaddr - base; 984 985 if (relofs < 0 || relofs >= p->_clustsize) 986 continue; 987 988 ofs = ofs + relofs; 989 nm_prdis("%s: return offset %d (cluster %d) for pointer %p", 990 p->name, ofs, i, vaddr); 991 return ofs; 992 } 993 nm_prerr("address %p is not contained inside any cluster (%s)", 994 vaddr, p->name); 995 return 0; /* An error occurred */ 996 } 997 998 /* Helper functions which convert virtual addresses to offsets */ 999 #define netmap_if_offset(n, v) \ 1000 netmap_obj_offset(&(n)->pools[NETMAP_IF_POOL], (v)) 1001 1002 #define netmap_ring_offset(n, v) \ 1003 ((n)->pools[NETMAP_IF_POOL].memtotal + \ 1004 netmap_obj_offset(&(n)->pools[NETMAP_RING_POOL], (v))) 1005 1006 static ssize_t 1007 netmap_mem2_if_offset(struct netmap_mem_d *nmd, const void *addr) 1008 { 1009 return netmap_if_offset(nmd, addr); 1010 } 1011 1012 /* 1013 * report the index, and use start position as a hint, 1014 * otherwise buffer allocation becomes terribly expensive. 1015 */ 1016 static void * 1017 netmap_obj_malloc(struct netmap_obj_pool *p, u_int len, uint32_t *start, uint32_t *index) 1018 { 1019 uint32_t i = 0; /* index in the bitmap */ 1020 uint32_t mask, j = 0; /* slot counter */ 1021 void *vaddr = NULL; 1022 1023 if (len > p->_objsize) { 1024 nm_prerr("%s request size %d too large", p->name, len); 1025 return NULL; 1026 } 1027 1028 if (p->objfree == 0) { 1029 nm_prerr("no more %s objects", p->name); 1030 return NULL; 1031 } 1032 if (start) 1033 i = *start; 1034 1035 /* termination is guaranteed by p->free, but better check bounds on i */ 1036 while (vaddr == NULL && i < p->bitmap_slots) { 1037 uint32_t cur = p->bitmap[i]; 1038 if (cur == 0) { /* bitmask is fully used */ 1039 i++; 1040 continue; 1041 } 1042 /* locate a slot */ 1043 for (j = 0, mask = 1; (cur & mask) == 0; j++, mask <<= 1) 1044 ; 1045 1046 p->bitmap[i] &= ~mask; /* mark object as in use */ 1047 p->objfree--; 1048 1049 vaddr = p->lut[i * 32 + j].vaddr; 1050 if (index) 1051 *index = i * 32 + j; 1052 } 1053 nm_prdis("%s allocator: allocated object @ [%d][%d]: vaddr %p",p->name, i, j, vaddr); 1054 1055 if (start) 1056 *start = i; 1057 return vaddr; 1058 } 1059 1060 1061 /* 1062 * free by index, not by address. 1063 * XXX should we also cleanup the content ? 1064 */ 1065 static int 1066 netmap_obj_free(struct netmap_obj_pool *p, uint32_t j) 1067 { 1068 uint32_t *ptr, mask; 1069 1070 if (j >= p->objtotal) { 1071 nm_prerr("invalid index %u, max %u", j, p->objtotal); 1072 return 1; 1073 } 1074 ptr = &p->bitmap[j / 32]; 1075 mask = (1 << (j % 32)); 1076 if (*ptr & mask) { 1077 nm_prerr("ouch, double free on buffer %d", j); 1078 return 1; 1079 } else { 1080 *ptr |= mask; 1081 p->objfree++; 1082 return 0; 1083 } 1084 } 1085 1086 /* 1087 * free by address. This is slow but is only used for a few 1088 * objects (rings, nifp) 1089 */ 1090 static void 1091 netmap_obj_free_va(struct netmap_obj_pool *p, void *vaddr) 1092 { 1093 u_int i, j, n = p->numclusters; 1094 1095 for (i = 0, j = 0; i < n; i++, j += p->_clustentries) { 1096 void *base = p->lut[i * p->_clustentries].vaddr; 1097 ssize_t relofs = (ssize_t) vaddr - (ssize_t) base; 1098 1099 /* Given address, is out of the scope of the current cluster.*/ 1100 if (base == NULL || vaddr < base || relofs >= p->_clustsize) 1101 continue; 1102 1103 j = j + relofs / p->_objsize; 1104 /* KASSERT(j != 0, ("Cannot free object 0")); */ 1105 netmap_obj_free(p, j); 1106 return; 1107 } 1108 nm_prerr("address %p is not contained inside any cluster (%s)", 1109 vaddr, p->name); 1110 } 1111 1112 unsigned 1113 netmap_mem_bufsize(struct netmap_mem_d *nmd) 1114 { 1115 return nmd->pools[NETMAP_BUF_POOL]._objsize; 1116 } 1117 1118 #define netmap_if_malloc(n, len) netmap_obj_malloc(&(n)->pools[NETMAP_IF_POOL], len, NULL, NULL) 1119 #define netmap_if_free(n, v) netmap_obj_free_va(&(n)->pools[NETMAP_IF_POOL], (v)) 1120 #define netmap_ring_malloc(n, len) netmap_obj_malloc(&(n)->pools[NETMAP_RING_POOL], len, NULL, NULL) 1121 #define netmap_ring_free(n, v) netmap_obj_free_va(&(n)->pools[NETMAP_RING_POOL], (v)) 1122 #define netmap_buf_malloc(n, _pos, _index) \ 1123 netmap_obj_malloc(&(n)->pools[NETMAP_BUF_POOL], netmap_mem_bufsize(n), _pos, _index) 1124 1125 1126 #if 0 /* currently unused */ 1127 /* Return the index associated to the given packet buffer */ 1128 #define netmap_buf_index(n, v) \ 1129 (netmap_obj_offset(&(n)->pools[NETMAP_BUF_POOL], (v)) / NETMAP_BDG_BUF_SIZE(n)) 1130 #endif 1131 1132 /* 1133 * allocate extra buffers in a linked list. 1134 * returns the actual number. 1135 */ 1136 uint32_t 1137 netmap_extra_alloc(struct netmap_adapter *na, uint32_t *head, uint32_t n) 1138 { 1139 struct netmap_mem_d *nmd = na->nm_mem; 1140 uint32_t i, pos = 0; /* opaque, scan position in the bitmap */ 1141 1142 NMA_LOCK(nmd); 1143 1144 *head = 0; /* default, 'null' index ie empty list */ 1145 for (i = 0 ; i < n; i++) { 1146 uint32_t cur = *head; /* save current head */ 1147 uint32_t *p = netmap_buf_malloc(nmd, &pos, head); 1148 if (p == NULL) { 1149 nm_prerr("no more buffers after %d of %d", i, n); 1150 *head = cur; /* restore */ 1151 break; 1152 } 1153 nm_prdis(5, "allocate buffer %d -> %d", *head, cur); 1154 *p = cur; /* link to previous head */ 1155 } 1156 1157 NMA_UNLOCK(nmd); 1158 1159 return i; 1160 } 1161 1162 static void 1163 netmap_extra_free(struct netmap_adapter *na, uint32_t head) 1164 { 1165 struct lut_entry *lut = na->na_lut.lut; 1166 struct netmap_mem_d *nmd = na->nm_mem; 1167 struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL]; 1168 uint32_t i, cur, *buf; 1169 1170 nm_prdis("freeing the extra list"); 1171 for (i = 0; head >=2 && head < p->objtotal; i++) { 1172 cur = head; 1173 buf = lut[head].vaddr; 1174 head = *buf; 1175 *buf = 0; 1176 if (netmap_obj_free(p, cur)) 1177 break; 1178 } 1179 if (head != 0) 1180 nm_prerr("breaking with head %d", head); 1181 if (netmap_debug & NM_DEBUG_MEM) 1182 nm_prinf("freed %d buffers", i); 1183 } 1184 1185 1186 /* Return nonzero on error */ 1187 static int 1188 netmap_new_bufs(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n) 1189 { 1190 struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL]; 1191 u_int i = 0; /* slot counter */ 1192 uint32_t pos = 0; /* slot in p->bitmap */ 1193 uint32_t index = 0; /* buffer index */ 1194 1195 for (i = 0; i < n; i++) { 1196 void *vaddr = netmap_buf_malloc(nmd, &pos, &index); 1197 if (vaddr == NULL) { 1198 nm_prerr("no more buffers after %d of %d", i, n); 1199 goto cleanup; 1200 } 1201 slot[i].buf_idx = index; 1202 slot[i].len = p->_objsize; 1203 slot[i].flags = 0; 1204 slot[i].ptr = 0; 1205 } 1206 1207 nm_prdis("%s: allocated %d buffers, %d available, first at %d", p->name, n, p->objfree, pos); 1208 return (0); 1209 1210 cleanup: 1211 while (i > 0) { 1212 i--; 1213 netmap_obj_free(p, slot[i].buf_idx); 1214 } 1215 bzero(slot, n * sizeof(slot[0])); 1216 return (ENOMEM); 1217 } 1218 1219 static void 1220 netmap_mem_set_ring(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n, uint32_t index) 1221 { 1222 struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL]; 1223 u_int i; 1224 1225 for (i = 0; i < n; i++) { 1226 slot[i].buf_idx = index; 1227 slot[i].len = p->_objsize; 1228 slot[i].flags = 0; 1229 } 1230 } 1231 1232 1233 static void 1234 netmap_free_buf(struct netmap_mem_d *nmd, uint32_t i) 1235 { 1236 struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL]; 1237 1238 if (i < 2 || i >= p->objtotal) { 1239 nm_prerr("Cannot free buf#%d: should be in [2, %d[", i, p->objtotal); 1240 return; 1241 } 1242 netmap_obj_free(p, i); 1243 } 1244 1245 1246 static void 1247 netmap_free_bufs(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n) 1248 { 1249 u_int i; 1250 1251 for (i = 0; i < n; i++) { 1252 if (slot[i].buf_idx > 1) 1253 netmap_free_buf(nmd, slot[i].buf_idx); 1254 } 1255 nm_prdis("%s: released some buffers, available: %u", 1256 p->name, p->objfree); 1257 } 1258 1259 static void 1260 netmap_reset_obj_allocator(struct netmap_obj_pool *p) 1261 { 1262 1263 if (p == NULL) 1264 return; 1265 if (p->bitmap) 1266 nm_os_free(p->bitmap); 1267 p->bitmap = NULL; 1268 if (p->invalid_bitmap) 1269 nm_os_free(p->invalid_bitmap); 1270 p->invalid_bitmap = NULL; 1271 if (!p->alloc_done) { 1272 /* allocation was done by somebody else. 1273 * Let them clean up after themselves. 1274 */ 1275 return; 1276 } 1277 if (p->lut) { 1278 u_int i; 1279 1280 /* 1281 * Free each cluster allocated in 1282 * netmap_finalize_obj_allocator(). The cluster start 1283 * addresses are stored at multiples of p->_clusterentries 1284 * in the lut. 1285 */ 1286 for (i = 0; i < p->objtotal; i += p->_clustentries) { 1287 free(p->lut[i].vaddr, M_NETMAP); 1288 } 1289 nm_free_lut(p->lut, p->objtotal); 1290 } 1291 p->lut = NULL; 1292 p->objtotal = 0; 1293 p->memtotal = 0; 1294 p->numclusters = 0; 1295 p->objfree = 0; 1296 p->alloc_done = 0; 1297 } 1298 1299 /* 1300 * Free all resources related to an allocator. 1301 */ 1302 static void 1303 netmap_destroy_obj_allocator(struct netmap_obj_pool *p) 1304 { 1305 if (p == NULL) 1306 return; 1307 netmap_reset_obj_allocator(p); 1308 } 1309 1310 /* 1311 * We receive a request for objtotal objects, of size objsize each. 1312 * Internally we may round up both numbers, as we allocate objects 1313 * in small clusters multiple of the page size. 1314 * We need to keep track of objtotal and clustentries, 1315 * as they are needed when freeing memory. 1316 * 1317 * XXX note -- userspace needs the buffers to be contiguous, 1318 * so we cannot afford gaps at the end of a cluster. 1319 */ 1320 1321 1322 /* call with NMA_LOCK held */ 1323 static int 1324 netmap_config_obj_allocator(struct netmap_obj_pool *p, u_int objtotal, u_int objsize) 1325 { 1326 int i; 1327 u_int clustsize; /* the cluster size, multiple of page size */ 1328 u_int clustentries; /* how many objects per entry */ 1329 1330 /* we store the current request, so we can 1331 * detect configuration changes later */ 1332 p->r_objtotal = objtotal; 1333 p->r_objsize = objsize; 1334 1335 #define MAX_CLUSTSIZE (1<<22) // 4 MB 1336 #define LINE_ROUND NM_BUF_ALIGN // 64 1337 if (objsize >= MAX_CLUSTSIZE) { 1338 /* we could do it but there is no point */ 1339 nm_prerr("unsupported allocation for %d bytes", objsize); 1340 return EINVAL; 1341 } 1342 /* make sure objsize is a multiple of LINE_ROUND */ 1343 i = (objsize & (LINE_ROUND - 1)); 1344 if (i) { 1345 nm_prinf("aligning object by %d bytes", LINE_ROUND - i); 1346 objsize += LINE_ROUND - i; 1347 } 1348 if (objsize < p->objminsize || objsize > p->objmaxsize) { 1349 nm_prerr("requested objsize %d out of range [%d, %d]", 1350 objsize, p->objminsize, p->objmaxsize); 1351 return EINVAL; 1352 } 1353 if (objtotal < p->nummin || objtotal > p->nummax) { 1354 nm_prerr("requested objtotal %d out of range [%d, %d]", 1355 objtotal, p->nummin, p->nummax); 1356 return EINVAL; 1357 } 1358 /* 1359 * Compute number of objects using a brute-force approach: 1360 * given a max cluster size, 1361 * we try to fill it with objects keeping track of the 1362 * wasted space to the next page boundary. 1363 */ 1364 for (clustentries = 0, i = 1;; i++) { 1365 u_int delta, used = i * objsize; 1366 if (used > MAX_CLUSTSIZE) 1367 break; 1368 delta = used % PAGE_SIZE; 1369 if (delta == 0) { // exact solution 1370 clustentries = i; 1371 break; 1372 } 1373 } 1374 /* exact solution not found */ 1375 if (clustentries == 0) { 1376 nm_prerr("unsupported allocation for %d bytes", objsize); 1377 return EINVAL; 1378 } 1379 /* compute clustsize */ 1380 clustsize = clustentries * objsize; 1381 if (netmap_debug & NM_DEBUG_MEM) 1382 nm_prinf("objsize %d clustsize %d objects %d", 1383 objsize, clustsize, clustentries); 1384 1385 /* 1386 * The number of clusters is n = ceil(objtotal/clustentries) 1387 * objtotal' = n * clustentries 1388 */ 1389 p->_clustentries = clustentries; 1390 p->_clustsize = clustsize; 1391 p->_numclusters = (objtotal + clustentries - 1) / clustentries; 1392 1393 /* actual values (may be larger than requested) */ 1394 p->_objsize = objsize; 1395 p->_objtotal = p->_numclusters * clustentries; 1396 1397 return 0; 1398 } 1399 1400 /* call with NMA_LOCK held */ 1401 static int 1402 netmap_finalize_obj_allocator(struct netmap_obj_pool *p) 1403 { 1404 int i; /* must be signed */ 1405 1406 if (p->lut) { 1407 /* if the lut is already there we assume that also all the 1408 * clusters have already been allocated, possibly by somebody 1409 * else (e.g., extmem). In the latter case, the alloc_done flag 1410 * will remain at zero, so that we will not attempt to 1411 * deallocate the clusters by ourselves in 1412 * netmap_reset_obj_allocator. 1413 */ 1414 return 0; 1415 } 1416 1417 /* optimistically assume we have enough memory */ 1418 p->numclusters = p->_numclusters; 1419 p->objtotal = p->_objtotal; 1420 p->alloc_done = 1; 1421 1422 p->lut = nm_alloc_lut(p->objtotal); 1423 if (p->lut == NULL) { 1424 nm_prerr("Unable to create lookup table for '%s'", p->name); 1425 goto clean; 1426 } 1427 1428 /* 1429 * Allocate clusters, init pointers 1430 */ 1431 1432 for (i = 0; i < (int)p->objtotal;) { 1433 int lim = i + p->_clustentries; 1434 char *clust; 1435 1436 /* 1437 * XXX Note, we only need contigmalloc() for buffers attached 1438 * to native interfaces. In all other cases (nifp, netmap rings 1439 * and even buffers for VALE ports or emulated interfaces) we 1440 * can live with standard malloc, because the hardware will not 1441 * access the pages directly. 1442 */ 1443 clust = contigmalloc(p->_clustsize, M_NETMAP, M_NOWAIT | M_ZERO, 1444 (size_t)0, -1UL, PAGE_SIZE, 0); 1445 if (clust == NULL) { 1446 /* 1447 * If we get here, there is a severe memory shortage, 1448 * so halve the allocated memory to reclaim some. 1449 */ 1450 nm_prerr("Unable to create cluster at %d for '%s' allocator", 1451 i, p->name); 1452 if (i < 2) /* nothing to halve */ 1453 goto out; 1454 lim = i / 2; 1455 for (i--; i >= lim; i--) { 1456 if (i % p->_clustentries == 0 && p->lut[i].vaddr) 1457 free(p->lut[i].vaddr, M_NETMAP); 1458 p->lut[i].vaddr = NULL; 1459 } 1460 out: 1461 p->objtotal = i; 1462 /* we may have stopped in the middle of a cluster */ 1463 p->numclusters = (i + p->_clustentries - 1) / p->_clustentries; 1464 break; 1465 } 1466 /* 1467 * Set lut state for all buffers in the current cluster. 1468 * 1469 * [i, lim) is the set of buffer indexes that cover the 1470 * current cluster. 1471 * 1472 * 'clust' is really the address of the current buffer in 1473 * the current cluster as we index through it with a stride 1474 * of p->_objsize. 1475 */ 1476 for (; i < lim; i++, clust += p->_objsize) { 1477 p->lut[i].vaddr = clust; 1478 #if !defined(linux) && !defined(_WIN32) 1479 p->lut[i].paddr = vtophys(clust); 1480 #endif 1481 } 1482 } 1483 p->memtotal = (size_t)p->numclusters * (size_t)p->_clustsize; 1484 if (netmap_verbose) 1485 nm_prinf("Pre-allocated %d clusters (%d/%zuKB) for '%s'", 1486 p->numclusters, p->_clustsize >> 10, 1487 p->memtotal >> 10, p->name); 1488 1489 return 0; 1490 1491 clean: 1492 netmap_reset_obj_allocator(p); 1493 return ENOMEM; 1494 } 1495 1496 /* call with lock held */ 1497 static int 1498 netmap_mem_params_changed(struct netmap_obj_params* p) 1499 { 1500 int i, rv = 0; 1501 1502 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1503 if (p[i].last_size != p[i].size || p[i].last_num != p[i].num) { 1504 p[i].last_size = p[i].size; 1505 p[i].last_num = p[i].num; 1506 rv = 1; 1507 } 1508 } 1509 return rv; 1510 } 1511 1512 static void 1513 netmap_mem_reset_all(struct netmap_mem_d *nmd) 1514 { 1515 int i; 1516 1517 if (netmap_debug & NM_DEBUG_MEM) 1518 nm_prinf("resetting %p", nmd); 1519 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1520 netmap_reset_obj_allocator(&nmd->pools[i]); 1521 } 1522 nmd->flags &= ~NETMAP_MEM_FINALIZED; 1523 } 1524 1525 static int 1526 netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na) 1527 { 1528 int i, lim = p->objtotal; 1529 struct netmap_lut *lut; 1530 if (na == NULL || na->pdev == NULL) 1531 return 0; 1532 1533 lut = &na->na_lut; 1534 1535 1536 1537 #if defined(__FreeBSD__) 1538 /* On FreeBSD mapping and unmapping is performed by the txsync 1539 * and rxsync routine, packet by packet. */ 1540 (void)i; 1541 (void)lim; 1542 (void)lut; 1543 #elif defined(_WIN32) 1544 (void)i; 1545 (void)lim; 1546 (void)lut; 1547 nm_prerr("unsupported on Windows"); 1548 #else /* linux */ 1549 nm_prdis("unmapping and freeing plut for %s", na->name); 1550 if (lut->plut == NULL || na->pdev == NULL) 1551 return 0; 1552 for (i = 0; i < lim; i += p->_clustentries) { 1553 if (lut->plut[i].paddr) 1554 netmap_unload_map(na, (bus_dma_tag_t) na->pdev, &lut->plut[i].paddr, p->_clustsize); 1555 } 1556 nm_free_plut(lut->plut); 1557 lut->plut = NULL; 1558 #endif /* linux */ 1559 1560 return 0; 1561 } 1562 1563 static int 1564 netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na) 1565 { 1566 int error = 0; 1567 int i, lim = p->objtotal; 1568 struct netmap_lut *lut = &na->na_lut; 1569 1570 if (na->pdev == NULL) 1571 return 0; 1572 1573 #if defined(__FreeBSD__) 1574 /* On FreeBSD mapping and unmapping is performed by the txsync 1575 * and rxsync routine, packet by packet. */ 1576 (void)i; 1577 (void)lim; 1578 (void)lut; 1579 #elif defined(_WIN32) 1580 (void)i; 1581 (void)lim; 1582 (void)lut; 1583 nm_prerr("unsupported on Windows"); 1584 #else /* linux */ 1585 1586 if (lut->plut != NULL) { 1587 nm_prdis("plut already allocated for %s", na->name); 1588 return 0; 1589 } 1590 1591 nm_prdis("allocating physical lut for %s", na->name); 1592 lut->plut = nm_alloc_plut(lim); 1593 if (lut->plut == NULL) { 1594 nm_prerr("Failed to allocate physical lut for %s", na->name); 1595 return ENOMEM; 1596 } 1597 1598 for (i = 0; i < lim; i += p->_clustentries) { 1599 lut->plut[i].paddr = 0; 1600 } 1601 1602 for (i = 0; i < lim; i += p->_clustentries) { 1603 int j; 1604 1605 if (p->lut[i].vaddr == NULL) 1606 continue; 1607 1608 error = netmap_load_map(na, (bus_dma_tag_t) na->pdev, &lut->plut[i].paddr, 1609 p->lut[i].vaddr, p->_clustsize); 1610 if (error) { 1611 nm_prerr("Failed to map cluster #%d from the %s pool", i, p->name); 1612 break; 1613 } 1614 1615 for (j = 1; j < p->_clustentries; j++) { 1616 lut->plut[i + j].paddr = lut->plut[i + j - 1].paddr + p->_objsize; 1617 } 1618 } 1619 1620 if (error) 1621 netmap_mem_unmap(p, na); 1622 1623 #endif /* linux */ 1624 1625 return error; 1626 } 1627 1628 static int 1629 netmap_mem_finalize_all(struct netmap_mem_d *nmd) 1630 { 1631 int i; 1632 if (nmd->flags & NETMAP_MEM_FINALIZED) 1633 return 0; 1634 nmd->lasterr = 0; 1635 nmd->nm_totalsize = 0; 1636 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1637 nmd->lasterr = netmap_finalize_obj_allocator(&nmd->pools[i]); 1638 if (nmd->lasterr) 1639 goto error; 1640 nmd->nm_totalsize += nmd->pools[i].memtotal; 1641 } 1642 nmd->nm_totalsize = (nmd->nm_totalsize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); 1643 nmd->lasterr = netmap_mem_init_bitmaps(nmd); 1644 if (nmd->lasterr) 1645 goto error; 1646 1647 nmd->flags |= NETMAP_MEM_FINALIZED; 1648 1649 if (netmap_verbose) 1650 nm_prinf("interfaces %zd KB, rings %zd KB, buffers %zd MB", 1651 nmd->pools[NETMAP_IF_POOL].memtotal >> 10, 1652 nmd->pools[NETMAP_RING_POOL].memtotal >> 10, 1653 nmd->pools[NETMAP_BUF_POOL].memtotal >> 20); 1654 1655 if (netmap_verbose) 1656 nm_prinf("Free buffers: %d", nmd->pools[NETMAP_BUF_POOL].objfree); 1657 1658 1659 return 0; 1660 error: 1661 netmap_mem_reset_all(nmd); 1662 return nmd->lasterr; 1663 } 1664 1665 /* 1666 * allocator for private memory 1667 */ 1668 static void * 1669 _netmap_mem_private_new(size_t size, struct netmap_obj_params *p, int grp_id, 1670 const struct netmap_mem_ops *ops, uint64_t memtotal, int *perr) 1671 { 1672 struct netmap_mem_d *d = NULL; 1673 int i, err = 0; 1674 int checksz = 0; 1675 1676 /* if memtotal is !=0 we check that the request fits the available 1677 * memory. Moreover, any surprlus memory is assigned to buffers. 1678 */ 1679 checksz = (memtotal > 0); 1680 1681 d = nm_os_malloc(size); 1682 if (d == NULL) { 1683 err = ENOMEM; 1684 goto error; 1685 } 1686 1687 *d = nm_blueprint; 1688 d->ops = ops; 1689 1690 err = nm_mem_assign_id(d, grp_id); 1691 if (err) 1692 goto error_free; 1693 snprintf(d->name, NM_MEM_NAMESZ, "%d", d->nm_id); 1694 1695 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1696 snprintf(d->pools[i].name, NETMAP_POOL_MAX_NAMSZ, 1697 nm_blueprint.pools[i].name, 1698 d->name); 1699 if (checksz) { 1700 uint64_t poolsz = (uint64_t)p[i].num * p[i].size; 1701 if (memtotal < poolsz) { 1702 nm_prerr("%s: request too large", d->pools[i].name); 1703 err = ENOMEM; 1704 goto error_rel_id; 1705 } 1706 memtotal -= poolsz; 1707 } 1708 d->params[i].num = p[i].num; 1709 d->params[i].size = p[i].size; 1710 } 1711 if (checksz && memtotal > 0) { 1712 uint64_t sz = d->params[NETMAP_BUF_POOL].size; 1713 uint64_t n = (memtotal + sz - 1) / sz; 1714 1715 if (n) { 1716 if (netmap_verbose) { 1717 nm_prinf("%s: adding %llu more buffers", 1718 d->pools[NETMAP_BUF_POOL].name, 1719 (unsigned long long)n); 1720 } 1721 d->params[NETMAP_BUF_POOL].num += n; 1722 } 1723 } 1724 1725 NMA_LOCK_INIT(d); 1726 1727 err = netmap_mem_config(d); 1728 if (err) 1729 goto error_destroy_lock; 1730 1731 d->flags &= ~NETMAP_MEM_FINALIZED; 1732 1733 return d; 1734 1735 error_destroy_lock: 1736 NMA_LOCK_DESTROY(d); 1737 error_rel_id: 1738 nm_mem_release_id(d); 1739 error_free: 1740 nm_os_free(d); 1741 error: 1742 if (perr) 1743 *perr = err; 1744 return NULL; 1745 } 1746 1747 struct netmap_mem_d * 1748 netmap_mem_private_new(u_int txr, u_int txd, u_int rxr, u_int rxd, 1749 u_int extra_bufs, u_int npipes, int *perr) 1750 { 1751 struct netmap_mem_d *d = NULL; 1752 struct netmap_obj_params p[NETMAP_POOLS_NR]; 1753 int i; 1754 u_int v, maxd; 1755 /* account for the fake host rings */ 1756 txr++; 1757 rxr++; 1758 1759 /* copy the min values */ 1760 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1761 p[i] = netmap_min_priv_params[i]; 1762 } 1763 1764 /* possibly increase them to fit user request */ 1765 v = sizeof(struct netmap_if) + sizeof(ssize_t) * (txr + rxr); 1766 if (p[NETMAP_IF_POOL].size < v) 1767 p[NETMAP_IF_POOL].size = v; 1768 v = 2 + 4 * npipes; 1769 if (p[NETMAP_IF_POOL].num < v) 1770 p[NETMAP_IF_POOL].num = v; 1771 maxd = (txd > rxd) ? txd : rxd; 1772 v = sizeof(struct netmap_ring) + sizeof(struct netmap_slot) * maxd; 1773 if (p[NETMAP_RING_POOL].size < v) 1774 p[NETMAP_RING_POOL].size = v; 1775 /* each pipe endpoint needs two tx rings (1 normal + 1 host, fake) 1776 * and two rx rings (again, 1 normal and 1 fake host) 1777 */ 1778 v = txr + rxr + 8 * npipes; 1779 if (p[NETMAP_RING_POOL].num < v) 1780 p[NETMAP_RING_POOL].num = v; 1781 /* for each pipe we only need the buffers for the 4 "real" rings. 1782 * On the other end, the pipe ring dimension may be different from 1783 * the parent port ring dimension. As a compromise, we allocate twice the 1784 * space actually needed if the pipe rings were the same size as the parent rings 1785 */ 1786 v = (4 * npipes + rxr) * rxd + (4 * npipes + txr) * txd + 2 + extra_bufs; 1787 /* the +2 is for the tx and rx fake buffers (indices 0 and 1) */ 1788 if (p[NETMAP_BUF_POOL].num < v) 1789 p[NETMAP_BUF_POOL].num = v; 1790 1791 if (netmap_verbose) 1792 nm_prinf("req if %d*%d ring %d*%d buf %d*%d", 1793 p[NETMAP_IF_POOL].num, 1794 p[NETMAP_IF_POOL].size, 1795 p[NETMAP_RING_POOL].num, 1796 p[NETMAP_RING_POOL].size, 1797 p[NETMAP_BUF_POOL].num, 1798 p[NETMAP_BUF_POOL].size); 1799 1800 d = _netmap_mem_private_new(sizeof(*d), p, -1, &netmap_mem_global_ops, 0, perr); 1801 1802 return d; 1803 } 1804 1805 /* Reference iommu allocator - find existing or create new, 1806 * for not hw addapeters fallback to global allocator. 1807 */ 1808 struct netmap_mem_d * 1809 netmap_mem_get_iommu(struct netmap_adapter *na) 1810 { 1811 int i, err, grp_id; 1812 struct netmap_mem_d *nmd; 1813 1814 if (na == NULL || na->pdev == NULL) 1815 return netmap_mem_get(&nm_mem); 1816 1817 grp_id = nm_iommu_group_id(na->pdev); 1818 1819 NM_MTX_LOCK(nm_mem_list_lock); 1820 nmd = netmap_last_mem_d; 1821 do { 1822 if (!(nmd->flags & NETMAP_MEM_HIDDEN) && nmd->nm_grp == grp_id) { 1823 nmd->refcount++; 1824 NM_DBG_REFC(nmd, __FUNCTION__, __LINE__); 1825 NM_MTX_UNLOCK(nm_mem_list_lock); 1826 return nmd; 1827 } 1828 nmd = nmd->next; 1829 } while (nmd != netmap_last_mem_d); 1830 1831 nmd = nm_os_malloc(sizeof(*nmd)); 1832 if (nmd == NULL) 1833 goto error; 1834 1835 *nmd = nm_mem_blueprint; 1836 1837 err = nm_mem_assign_id_locked(nmd, grp_id); 1838 if (err) 1839 goto error_free; 1840 1841 snprintf(nmd->name, sizeof(nmd->name), "%d", nmd->nm_id); 1842 1843 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1844 snprintf(nmd->pools[i].name, NETMAP_POOL_MAX_NAMSZ, "%s-%s", 1845 nm_mem_blueprint.pools[i].name, nmd->name); 1846 } 1847 1848 NMA_LOCK_INIT(nmd); 1849 1850 NM_MTX_UNLOCK(nm_mem_list_lock); 1851 return nmd; 1852 1853 error_free: 1854 nm_os_free(nmd); 1855 error: 1856 NM_MTX_UNLOCK(nm_mem_list_lock); 1857 return NULL; 1858 } 1859 1860 /* call with lock held */ 1861 static int 1862 netmap_mem2_config(struct netmap_mem_d *nmd) 1863 { 1864 int i; 1865 1866 if (!netmap_mem_params_changed(nmd->params)) 1867 goto out; 1868 1869 nm_prdis("reconfiguring"); 1870 1871 if (nmd->flags & NETMAP_MEM_FINALIZED) { 1872 /* reset previous allocation */ 1873 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1874 netmap_reset_obj_allocator(&nmd->pools[i]); 1875 } 1876 nmd->flags &= ~NETMAP_MEM_FINALIZED; 1877 } 1878 1879 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1880 nmd->lasterr = netmap_config_obj_allocator(&nmd->pools[i], 1881 nmd->params[i].num, nmd->params[i].size); 1882 if (nmd->lasterr) 1883 goto out; 1884 } 1885 1886 out: 1887 1888 return nmd->lasterr; 1889 } 1890 1891 static int 1892 netmap_mem2_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na) 1893 { 1894 if (nmd->flags & NETMAP_MEM_FINALIZED) 1895 goto out; 1896 1897 if (netmap_mem_finalize_all(nmd)) 1898 goto out; 1899 1900 nmd->lasterr = 0; 1901 1902 out: 1903 return nmd->lasterr; 1904 } 1905 1906 static void 1907 netmap_mem2_delete(struct netmap_mem_d *nmd) 1908 { 1909 int i; 1910 1911 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1912 netmap_destroy_obj_allocator(&nmd->pools[i]); 1913 } 1914 1915 NMA_LOCK_DESTROY(nmd); 1916 if (nmd != &nm_mem) 1917 nm_os_free(nmd); 1918 } 1919 1920 #ifdef WITH_EXTMEM 1921 /* doubly linekd list of all existing external allocators */ 1922 static struct netmap_mem_ext *netmap_mem_ext_list = NULL; 1923 NM_MTX_T nm_mem_ext_list_lock; 1924 #endif /* WITH_EXTMEM */ 1925 1926 int 1927 netmap_mem_init(void) 1928 { 1929 nm_mem_blueprint = nm_mem; 1930 NM_MTX_INIT(nm_mem_list_lock); 1931 NMA_LOCK_INIT(&nm_mem); 1932 netmap_mem_get(&nm_mem); 1933 #ifdef WITH_EXTMEM 1934 NM_MTX_INIT(nm_mem_ext_list_lock); 1935 #endif /* WITH_EXTMEM */ 1936 return (0); 1937 } 1938 1939 void 1940 netmap_mem_fini(void) 1941 { 1942 netmap_mem_put(&nm_mem); 1943 } 1944 1945 static int 1946 netmap_mem_ring_needed(struct netmap_kring *kring) 1947 { 1948 return kring->ring == NULL && 1949 (kring->users > 0 || 1950 (kring->nr_kflags & NKR_NEEDRING)); 1951 } 1952 1953 static int 1954 netmap_mem_ring_todelete(struct netmap_kring *kring) 1955 { 1956 return kring->ring != NULL && 1957 kring->users == 0 && 1958 !(kring->nr_kflags & NKR_NEEDRING); 1959 } 1960 1961 1962 /* call with NMA_LOCK held * 1963 * 1964 * Allocate netmap rings and buffers for this card 1965 * The rings are contiguous, but have variable size. 1966 * The kring array must follow the layout described 1967 * in netmap_krings_create(). 1968 */ 1969 static int 1970 netmap_mem2_rings_create(struct netmap_mem_d *nmd, struct netmap_adapter *na) 1971 { 1972 enum txrx t; 1973 1974 for_rx_tx(t) { 1975 u_int i; 1976 1977 for (i = 0; i < netmap_all_rings(na, t); i++) { 1978 struct netmap_kring *kring = NMR(na, t)[i]; 1979 struct netmap_ring *ring = kring->ring; 1980 u_int len, ndesc; 1981 1982 if (!netmap_mem_ring_needed(kring)) { 1983 /* unneeded, or already created by somebody else */ 1984 if (netmap_debug & NM_DEBUG_MEM) 1985 nm_prinf("NOT creating ring %s (ring %p, users %d neekring %d)", 1986 kring->name, ring, kring->users, kring->nr_kflags & NKR_NEEDRING); 1987 continue; 1988 } 1989 if (netmap_debug & NM_DEBUG_MEM) 1990 nm_prinf("creating %s", kring->name); 1991 ndesc = kring->nkr_num_slots; 1992 len = sizeof(struct netmap_ring) + 1993 ndesc * sizeof(struct netmap_slot); 1994 ring = netmap_ring_malloc(nmd, len); 1995 if (ring == NULL) { 1996 nm_prerr("Cannot allocate %s_ring", nm_txrx2str(t)); 1997 goto cleanup; 1998 } 1999 nm_prdis("txring at %p", ring); 2000 kring->ring = ring; 2001 *(uint32_t *)(uintptr_t)&ring->num_slots = ndesc; 2002 *(int64_t *)(uintptr_t)&ring->buf_ofs = 2003 (nmd->pools[NETMAP_IF_POOL].memtotal + 2004 nmd->pools[NETMAP_RING_POOL].memtotal) - 2005 netmap_ring_offset(nmd, ring); 2006 2007 /* copy values from kring */ 2008 ring->head = kring->rhead; 2009 ring->cur = kring->rcur; 2010 ring->tail = kring->rtail; 2011 *(uint32_t *)(uintptr_t)&ring->nr_buf_size = 2012 netmap_mem_bufsize(nmd); 2013 nm_prdis("%s h %d c %d t %d", kring->name, 2014 ring->head, ring->cur, ring->tail); 2015 nm_prdis("initializing slots for %s_ring", nm_txrx2str(t)); 2016 if (!(kring->nr_kflags & NKR_FAKERING)) { 2017 /* this is a real ring */ 2018 if (netmap_debug & NM_DEBUG_MEM) 2019 nm_prinf("allocating buffers for %s", kring->name); 2020 if (netmap_new_bufs(nmd, ring->slot, ndesc)) { 2021 nm_prerr("Cannot allocate buffers for %s_ring", nm_txrx2str(t)); 2022 goto cleanup; 2023 } 2024 } else { 2025 /* this is a fake ring, set all indices to 0 */ 2026 if (netmap_debug & NM_DEBUG_MEM) 2027 nm_prinf("NOT allocating buffers for %s", kring->name); 2028 netmap_mem_set_ring(nmd, ring->slot, ndesc, 0); 2029 } 2030 /* ring info */ 2031 *(uint16_t *)(uintptr_t)&ring->ringid = kring->ring_id; 2032 *(uint16_t *)(uintptr_t)&ring->dir = kring->tx; 2033 } 2034 } 2035 2036 return 0; 2037 2038 cleanup: 2039 /* we cannot actually cleanup here, since we don't own kring->users 2040 * and kring->nr_klags & NKR_NEEDRING. The caller must decrement 2041 * the first or zero-out the second, then call netmap_free_rings() 2042 * to do the cleanup 2043 */ 2044 2045 return ENOMEM; 2046 } 2047 2048 static void 2049 netmap_mem2_rings_delete(struct netmap_mem_d *nmd, struct netmap_adapter *na) 2050 { 2051 enum txrx t; 2052 2053 for_rx_tx(t) { 2054 u_int i; 2055 for (i = 0; i < netmap_all_rings(na, t); i++) { 2056 struct netmap_kring *kring = NMR(na, t)[i]; 2057 struct netmap_ring *ring = kring->ring; 2058 2059 if (!netmap_mem_ring_todelete(kring)) { 2060 if (netmap_debug & NM_DEBUG_MEM) 2061 nm_prinf("NOT deleting ring %s (ring %p, users %d neekring %d)", 2062 kring->name, ring, kring->users, kring->nr_kflags & NKR_NEEDRING); 2063 continue; 2064 } 2065 if (netmap_debug & NM_DEBUG_MEM) 2066 nm_prinf("deleting ring %s", kring->name); 2067 if (!(kring->nr_kflags & NKR_FAKERING)) { 2068 nm_prdis("freeing bufs for %s", kring->name); 2069 netmap_free_bufs(nmd, ring->slot, kring->nkr_num_slots); 2070 } else { 2071 nm_prdis("NOT freeing bufs for %s", kring->name); 2072 } 2073 netmap_ring_free(nmd, ring); 2074 kring->ring = NULL; 2075 } 2076 } 2077 } 2078 2079 /* call with NMA_LOCK held */ 2080 /* 2081 * Allocate the per-fd structure netmap_if. 2082 * 2083 * We assume that the configuration stored in na 2084 * (number of tx/rx rings and descs) does not change while 2085 * the interface is in netmap mode. 2086 */ 2087 static struct netmap_if * 2088 netmap_mem2_if_new(struct netmap_mem_d *nmd, 2089 struct netmap_adapter *na, struct netmap_priv_d *priv) 2090 { 2091 struct netmap_if *nifp; 2092 ssize_t base; /* handy for relative offsets between rings and nifp */ 2093 u_int i, len, n[NR_TXRX], ntot; 2094 enum txrx t; 2095 2096 ntot = 0; 2097 for_rx_tx(t) { 2098 /* account for the (eventually fake) host rings */ 2099 n[t] = netmap_all_rings(na, t); 2100 ntot += n[t]; 2101 } 2102 /* 2103 * the descriptor is followed inline by an array of offsets 2104 * to the tx and rx rings in the shared memory region. 2105 */ 2106 2107 len = sizeof(struct netmap_if) + (ntot * sizeof(ssize_t)); 2108 nifp = netmap_if_malloc(nmd, len); 2109 if (nifp == NULL) { 2110 return NULL; 2111 } 2112 2113 /* initialize base fields -- override const */ 2114 *(u_int *)(uintptr_t)&nifp->ni_tx_rings = na->num_tx_rings; 2115 *(u_int *)(uintptr_t)&nifp->ni_rx_rings = na->num_rx_rings; 2116 *(u_int *)(uintptr_t)&nifp->ni_host_tx_rings = 2117 (na->num_host_tx_rings ? na->num_host_tx_rings : 1); 2118 *(u_int *)(uintptr_t)&nifp->ni_host_rx_rings = 2119 (na->num_host_rx_rings ? na->num_host_rx_rings : 1); 2120 strlcpy(nifp->ni_name, na->name, sizeof(nifp->ni_name)); 2121 2122 /* 2123 * fill the slots for the rx and tx rings. They contain the offset 2124 * between the ring and nifp, so the information is usable in 2125 * userspace to reach the ring from the nifp. 2126 */ 2127 base = netmap_if_offset(nmd, nifp); 2128 for (i = 0; i < n[NR_TX]; i++) { 2129 /* XXX instead of ofs == 0 maybe use the offset of an error 2130 * ring, like we do for buffers? */ 2131 ssize_t ofs = 0; 2132 2133 if (na->tx_rings[i]->ring != NULL && i >= priv->np_qfirst[NR_TX] 2134 && i < priv->np_qlast[NR_TX]) { 2135 ofs = netmap_ring_offset(nmd, 2136 na->tx_rings[i]->ring) - base; 2137 } 2138 *(ssize_t *)(uintptr_t)&nifp->ring_ofs[i] = ofs; 2139 } 2140 for (i = 0; i < n[NR_RX]; i++) { 2141 /* XXX instead of ofs == 0 maybe use the offset of an error 2142 * ring, like we do for buffers? */ 2143 ssize_t ofs = 0; 2144 2145 if (na->rx_rings[i]->ring != NULL && i >= priv->np_qfirst[NR_RX] 2146 && i < priv->np_qlast[NR_RX]) { 2147 ofs = netmap_ring_offset(nmd, 2148 na->rx_rings[i]->ring) - base; 2149 } 2150 *(ssize_t *)(uintptr_t)&nifp->ring_ofs[i+n[NR_TX]] = ofs; 2151 } 2152 2153 return (nifp); 2154 } 2155 2156 static void 2157 netmap_mem2_if_delete(struct netmap_mem_d *nmd, 2158 struct netmap_adapter *na, struct netmap_if *nifp) 2159 { 2160 if (nifp == NULL) 2161 /* nothing to do */ 2162 return; 2163 if (nifp->ni_bufs_head) 2164 netmap_extra_free(na, nifp->ni_bufs_head); 2165 netmap_if_free(nmd, nifp); 2166 } 2167 2168 static void 2169 netmap_mem2_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na) 2170 { 2171 2172 if (netmap_debug & NM_DEBUG_MEM) 2173 nm_prinf("active = %d", nmd->active); 2174 2175 } 2176 2177 const struct netmap_mem_ops netmap_mem_global_ops = { 2178 .nmd_get_lut = netmap_mem2_get_lut, 2179 .nmd_get_info = netmap_mem2_get_info, 2180 .nmd_ofstophys = netmap_mem2_ofstophys, 2181 .nmd_config = netmap_mem2_config, 2182 .nmd_finalize = netmap_mem2_finalize, 2183 .nmd_deref = netmap_mem2_deref, 2184 .nmd_delete = netmap_mem2_delete, 2185 .nmd_if_offset = netmap_mem2_if_offset, 2186 .nmd_if_new = netmap_mem2_if_new, 2187 .nmd_if_delete = netmap_mem2_if_delete, 2188 .nmd_rings_create = netmap_mem2_rings_create, 2189 .nmd_rings_delete = netmap_mem2_rings_delete 2190 }; 2191 2192 int 2193 netmap_mem_pools_info_get(struct nmreq_pools_info *req, 2194 struct netmap_mem_d *nmd) 2195 { 2196 int ret; 2197 2198 ret = netmap_mem_get_info(nmd, &req->nr_memsize, NULL, 2199 &req->nr_mem_id); 2200 if (ret) { 2201 return ret; 2202 } 2203 2204 NMA_LOCK(nmd); 2205 req->nr_if_pool_offset = 0; 2206 req->nr_if_pool_objtotal = nmd->pools[NETMAP_IF_POOL].objtotal; 2207 req->nr_if_pool_objsize = nmd->pools[NETMAP_IF_POOL]._objsize; 2208 2209 req->nr_ring_pool_offset = nmd->pools[NETMAP_IF_POOL].memtotal; 2210 req->nr_ring_pool_objtotal = nmd->pools[NETMAP_RING_POOL].objtotal; 2211 req->nr_ring_pool_objsize = nmd->pools[NETMAP_RING_POOL]._objsize; 2212 2213 req->nr_buf_pool_offset = nmd->pools[NETMAP_IF_POOL].memtotal + 2214 nmd->pools[NETMAP_RING_POOL].memtotal; 2215 req->nr_buf_pool_objtotal = nmd->pools[NETMAP_BUF_POOL].objtotal; 2216 req->nr_buf_pool_objsize = nmd->pools[NETMAP_BUF_POOL]._objsize; 2217 NMA_UNLOCK(nmd); 2218 2219 return 0; 2220 } 2221 2222 #ifdef WITH_EXTMEM 2223 struct netmap_mem_ext { 2224 struct netmap_mem_d up; 2225 2226 struct nm_os_extmem *os; 2227 struct netmap_mem_ext *next, *prev; 2228 }; 2229 2230 /* call with nm_mem_list_lock held */ 2231 static void 2232 netmap_mem_ext_register(struct netmap_mem_ext *e) 2233 { 2234 NM_MTX_LOCK(nm_mem_ext_list_lock); 2235 if (netmap_mem_ext_list) 2236 netmap_mem_ext_list->prev = e; 2237 e->next = netmap_mem_ext_list; 2238 netmap_mem_ext_list = e; 2239 e->prev = NULL; 2240 NM_MTX_UNLOCK(nm_mem_ext_list_lock); 2241 } 2242 2243 /* call with nm_mem_list_lock held */ 2244 static void 2245 netmap_mem_ext_unregister(struct netmap_mem_ext *e) 2246 { 2247 if (e->prev) 2248 e->prev->next = e->next; 2249 else 2250 netmap_mem_ext_list = e->next; 2251 if (e->next) 2252 e->next->prev = e->prev; 2253 e->prev = e->next = NULL; 2254 } 2255 2256 static struct netmap_mem_ext * 2257 netmap_mem_ext_search(struct nm_os_extmem *os) 2258 { 2259 struct netmap_mem_ext *e; 2260 2261 NM_MTX_LOCK(nm_mem_ext_list_lock); 2262 for (e = netmap_mem_ext_list; e; e = e->next) { 2263 if (nm_os_extmem_isequal(e->os, os)) { 2264 netmap_mem_get(&e->up); 2265 break; 2266 } 2267 } 2268 NM_MTX_UNLOCK(nm_mem_ext_list_lock); 2269 return e; 2270 } 2271 2272 2273 static void 2274 netmap_mem_ext_delete(struct netmap_mem_d *d) 2275 { 2276 int i; 2277 struct netmap_mem_ext *e = 2278 (struct netmap_mem_ext *)d; 2279 2280 netmap_mem_ext_unregister(e); 2281 2282 for (i = 0; i < NETMAP_POOLS_NR; i++) { 2283 struct netmap_obj_pool *p = &d->pools[i]; 2284 2285 if (p->lut) { 2286 nm_free_lut(p->lut, p->objtotal); 2287 p->lut = NULL; 2288 } 2289 } 2290 if (e->os) 2291 nm_os_extmem_delete(e->os); 2292 netmap_mem2_delete(d); 2293 } 2294 2295 static int 2296 netmap_mem_ext_config(struct netmap_mem_d *nmd) 2297 { 2298 return 0; 2299 } 2300 2301 struct netmap_mem_ops netmap_mem_ext_ops = { 2302 .nmd_get_lut = netmap_mem2_get_lut, 2303 .nmd_get_info = netmap_mem2_get_info, 2304 .nmd_ofstophys = netmap_mem2_ofstophys, 2305 .nmd_config = netmap_mem_ext_config, 2306 .nmd_finalize = netmap_mem2_finalize, 2307 .nmd_deref = netmap_mem2_deref, 2308 .nmd_delete = netmap_mem_ext_delete, 2309 .nmd_if_offset = netmap_mem2_if_offset, 2310 .nmd_if_new = netmap_mem2_if_new, 2311 .nmd_if_delete = netmap_mem2_if_delete, 2312 .nmd_rings_create = netmap_mem2_rings_create, 2313 .nmd_rings_delete = netmap_mem2_rings_delete 2314 }; 2315 2316 struct netmap_mem_d * 2317 netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror) 2318 { 2319 int error = 0; 2320 int i, j; 2321 struct netmap_mem_ext *nme; 2322 char *clust; 2323 size_t off; 2324 struct nm_os_extmem *os = NULL; 2325 int nr_pages; 2326 2327 // XXX sanity checks 2328 if (pi->nr_if_pool_objtotal == 0) 2329 pi->nr_if_pool_objtotal = netmap_min_priv_params[NETMAP_IF_POOL].num; 2330 if (pi->nr_if_pool_objsize == 0) 2331 pi->nr_if_pool_objsize = netmap_min_priv_params[NETMAP_IF_POOL].size; 2332 if (pi->nr_ring_pool_objtotal == 0) 2333 pi->nr_ring_pool_objtotal = netmap_min_priv_params[NETMAP_RING_POOL].num; 2334 if (pi->nr_ring_pool_objsize == 0) 2335 pi->nr_ring_pool_objsize = netmap_min_priv_params[NETMAP_RING_POOL].size; 2336 if (pi->nr_buf_pool_objtotal == 0) 2337 pi->nr_buf_pool_objtotal = netmap_min_priv_params[NETMAP_BUF_POOL].num; 2338 if (pi->nr_buf_pool_objsize == 0) 2339 pi->nr_buf_pool_objsize = netmap_min_priv_params[NETMAP_BUF_POOL].size; 2340 if (netmap_verbose & NM_DEBUG_MEM) 2341 nm_prinf("if %d %d ring %d %d buf %d %d", 2342 pi->nr_if_pool_objtotal, pi->nr_if_pool_objsize, 2343 pi->nr_ring_pool_objtotal, pi->nr_ring_pool_objsize, 2344 pi->nr_buf_pool_objtotal, pi->nr_buf_pool_objsize); 2345 2346 os = nm_os_extmem_create(usrptr, pi, &error); 2347 if (os == NULL) { 2348 nm_prerr("os extmem creation failed"); 2349 goto out; 2350 } 2351 2352 nme = netmap_mem_ext_search(os); 2353 if (nme) { 2354 nm_os_extmem_delete(os); 2355 return &nme->up; 2356 } 2357 if (netmap_verbose & NM_DEBUG_MEM) 2358 nm_prinf("not found, creating new"); 2359 2360 nme = _netmap_mem_private_new(sizeof(*nme), 2361 2362 (struct netmap_obj_params[]){ 2363 { pi->nr_if_pool_objsize, pi->nr_if_pool_objtotal }, 2364 { pi->nr_ring_pool_objsize, pi->nr_ring_pool_objtotal }, 2365 { pi->nr_buf_pool_objsize, pi->nr_buf_pool_objtotal }}, 2366 -1, 2367 &netmap_mem_ext_ops, 2368 pi->nr_memsize, 2369 &error); 2370 if (nme == NULL) 2371 goto out_unmap; 2372 2373 nr_pages = nm_os_extmem_nr_pages(os); 2374 2375 /* from now on pages will be released by nme destructor; 2376 * we let res = 0 to prevent release in out_unmap below 2377 */ 2378 nme->os = os; 2379 os = NULL; /* pass ownership */ 2380 2381 clust = nm_os_extmem_nextpage(nme->os); 2382 off = 0; 2383 for (i = 0; i < NETMAP_POOLS_NR; i++) { 2384 struct netmap_obj_pool *p = &nme->up.pools[i]; 2385 struct netmap_obj_params *o = &nme->up.params[i]; 2386 2387 p->_objsize = o->size; 2388 p->_clustsize = o->size; 2389 p->_clustentries = 1; 2390 2391 p->lut = nm_alloc_lut(o->num); 2392 if (p->lut == NULL) { 2393 error = ENOMEM; 2394 goto out_delete; 2395 } 2396 2397 p->bitmap_slots = (o->num + sizeof(uint32_t) - 1) / sizeof(uint32_t); 2398 p->invalid_bitmap = nm_os_malloc(sizeof(uint32_t) * p->bitmap_slots); 2399 if (p->invalid_bitmap == NULL) { 2400 error = ENOMEM; 2401 goto out_delete; 2402 } 2403 2404 if (nr_pages == 0) { 2405 p->objtotal = 0; 2406 p->memtotal = 0; 2407 p->objfree = 0; 2408 continue; 2409 } 2410 2411 for (j = 0; j < o->num && nr_pages > 0; j++) { 2412 size_t noff; 2413 2414 p->lut[j].vaddr = clust + off; 2415 #if !defined(linux) && !defined(_WIN32) 2416 p->lut[j].paddr = vtophys(p->lut[j].vaddr); 2417 #endif 2418 nm_prdis("%s %d at %p", p->name, j, p->lut[j].vaddr); 2419 noff = off + p->_objsize; 2420 if (noff < PAGE_SIZE) { 2421 off = noff; 2422 continue; 2423 } 2424 nm_prdis("too big, recomputing offset..."); 2425 while (noff >= PAGE_SIZE) { 2426 char *old_clust = clust; 2427 noff -= PAGE_SIZE; 2428 clust = nm_os_extmem_nextpage(nme->os); 2429 nr_pages--; 2430 nm_prdis("noff %zu page %p nr_pages %d", noff, 2431 page_to_virt(*pages), nr_pages); 2432 if (noff > 0 && !nm_isset(p->invalid_bitmap, j) && 2433 (nr_pages == 0 || 2434 old_clust + PAGE_SIZE != clust)) 2435 { 2436 /* out of space or non contiguous, 2437 * drop this object 2438 * */ 2439 p->invalid_bitmap[ (j>>5) ] |= 1U << (j & 31U); 2440 nm_prdis("non contiguous at off %zu, drop", noff); 2441 } 2442 if (nr_pages == 0) 2443 break; 2444 } 2445 off = noff; 2446 } 2447 p->objtotal = j; 2448 p->numclusters = p->objtotal; 2449 p->memtotal = j * (size_t)p->_objsize; 2450 nm_prdis("%d memtotal %zu", j, p->memtotal); 2451 } 2452 2453 netmap_mem_ext_register(nme); 2454 2455 return &nme->up; 2456 2457 out_delete: 2458 netmap_mem_put(&nme->up); 2459 out_unmap: 2460 if (os) 2461 nm_os_extmem_delete(os); 2462 out: 2463 if (perror) 2464 *perror = error; 2465 return NULL; 2466 2467 } 2468 #endif /* WITH_EXTMEM */ 2469 2470 2471 #ifdef WITH_PTNETMAP 2472 struct mem_pt_if { 2473 struct mem_pt_if *next; 2474 if_t ifp; 2475 unsigned int nifp_offset; 2476 }; 2477 2478 /* Netmap allocator for ptnetmap guests. */ 2479 struct netmap_mem_ptg { 2480 struct netmap_mem_d up; 2481 2482 vm_paddr_t nm_paddr; /* physical address in the guest */ 2483 void *nm_addr; /* virtual address in the guest */ 2484 struct netmap_lut buf_lut; /* lookup table for BUF pool in the guest */ 2485 nm_memid_t host_mem_id; /* allocator identifier in the host */ 2486 struct ptnetmap_memdev *ptn_dev;/* ptnetmap memdev */ 2487 struct mem_pt_if *pt_ifs; /* list of interfaces in passthrough */ 2488 }; 2489 2490 /* Link a passthrough interface to a passthrough netmap allocator. */ 2491 static int 2492 netmap_mem_pt_guest_ifp_add(struct netmap_mem_d *nmd, if_t ifp, 2493 unsigned int nifp_offset) 2494 { 2495 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2496 struct mem_pt_if *ptif = nm_os_malloc(sizeof(*ptif)); 2497 2498 if (!ptif) { 2499 return ENOMEM; 2500 } 2501 2502 NMA_LOCK(nmd); 2503 2504 ptif->ifp = ifp; 2505 ptif->nifp_offset = nifp_offset; 2506 2507 if (ptnmd->pt_ifs) { 2508 ptif->next = ptnmd->pt_ifs; 2509 } 2510 ptnmd->pt_ifs = ptif; 2511 2512 NMA_UNLOCK(nmd); 2513 2514 nm_prinf("ifp=%s,nifp_offset=%u", 2515 if_name(ptif->ifp), ptif->nifp_offset); 2516 2517 return 0; 2518 } 2519 2520 /* Called with NMA_LOCK(nmd) held. */ 2521 static struct mem_pt_if * 2522 netmap_mem_pt_guest_ifp_lookup(struct netmap_mem_d *nmd, if_t ifp) 2523 { 2524 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2525 struct mem_pt_if *curr; 2526 2527 for (curr = ptnmd->pt_ifs; curr; curr = curr->next) { 2528 if (curr->ifp == ifp) { 2529 return curr; 2530 } 2531 } 2532 2533 return NULL; 2534 } 2535 2536 /* Unlink a passthrough interface from a passthrough netmap allocator. */ 2537 int 2538 netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *nmd, if_t ifp) 2539 { 2540 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2541 struct mem_pt_if *prev = NULL; 2542 struct mem_pt_if *curr; 2543 int ret = -1; 2544 2545 NMA_LOCK(nmd); 2546 2547 for (curr = ptnmd->pt_ifs; curr; curr = curr->next) { 2548 if (curr->ifp == ifp) { 2549 if (prev) { 2550 prev->next = curr->next; 2551 } else { 2552 ptnmd->pt_ifs = curr->next; 2553 } 2554 nm_prinf("removed (ifp=%s,nifp_offset=%u)", 2555 if_name(curr->ifp), curr->nifp_offset); 2556 nm_os_free(curr); 2557 ret = 0; 2558 break; 2559 } 2560 prev = curr; 2561 } 2562 2563 NMA_UNLOCK(nmd); 2564 2565 return ret; 2566 } 2567 2568 static int 2569 netmap_mem_pt_guest_get_lut(struct netmap_mem_d *nmd, struct netmap_lut *lut) 2570 { 2571 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2572 2573 if (!(nmd->flags & NETMAP_MEM_FINALIZED)) { 2574 return EINVAL; 2575 } 2576 2577 *lut = ptnmd->buf_lut; 2578 return 0; 2579 } 2580 2581 static int 2582 netmap_mem_pt_guest_get_info(struct netmap_mem_d *nmd, uint64_t *size, 2583 u_int *memflags, uint16_t *id) 2584 { 2585 int error = 0; 2586 2587 error = nmd->ops->nmd_config(nmd); 2588 if (error) 2589 goto out; 2590 2591 if (size) 2592 *size = nmd->nm_totalsize; 2593 if (memflags) 2594 *memflags = nmd->flags; 2595 if (id) 2596 *id = nmd->nm_id; 2597 2598 out: 2599 2600 return error; 2601 } 2602 2603 static vm_paddr_t 2604 netmap_mem_pt_guest_ofstophys(struct netmap_mem_d *nmd, vm_ooffset_t off) 2605 { 2606 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2607 vm_paddr_t paddr; 2608 /* if the offset is valid, just return csb->base_addr + off */ 2609 paddr = (vm_paddr_t)(ptnmd->nm_paddr + off); 2610 nm_prdis("off %lx padr %lx", off, (unsigned long)paddr); 2611 return paddr; 2612 } 2613 2614 static int 2615 netmap_mem_pt_guest_config(struct netmap_mem_d *nmd) 2616 { 2617 /* nothing to do, we are configured on creation 2618 * and configuration never changes thereafter 2619 */ 2620 return 0; 2621 } 2622 2623 static int 2624 netmap_mem_pt_guest_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na) 2625 { 2626 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2627 uint64_t mem_size; 2628 uint32_t bufsize; 2629 uint32_t nbuffers; 2630 uint32_t poolofs; 2631 vm_paddr_t paddr; 2632 char *vaddr; 2633 int i; 2634 int error = 0; 2635 2636 if (nmd->flags & NETMAP_MEM_FINALIZED) 2637 goto out; 2638 2639 if (ptnmd->ptn_dev == NULL) { 2640 nm_prerr("ptnetmap memdev not attached"); 2641 error = ENOMEM; 2642 goto out; 2643 } 2644 /* Map memory through ptnetmap-memdev BAR. */ 2645 error = nm_os_pt_memdev_iomap(ptnmd->ptn_dev, &ptnmd->nm_paddr, 2646 &ptnmd->nm_addr, &mem_size); 2647 if (error) 2648 goto out; 2649 2650 /* Initialize the lut using the information contained in the 2651 * ptnetmap memory device. */ 2652 bufsize = nm_os_pt_memdev_ioread(ptnmd->ptn_dev, 2653 PTNET_MDEV_IO_BUF_POOL_OBJSZ); 2654 nbuffers = nm_os_pt_memdev_ioread(ptnmd->ptn_dev, 2655 PTNET_MDEV_IO_BUF_POOL_OBJNUM); 2656 2657 /* allocate the lut */ 2658 if (ptnmd->buf_lut.lut == NULL) { 2659 nm_prinf("allocating lut"); 2660 ptnmd->buf_lut.lut = nm_alloc_lut(nbuffers); 2661 if (ptnmd->buf_lut.lut == NULL) { 2662 nm_prerr("lut allocation failed"); 2663 return ENOMEM; 2664 } 2665 } 2666 2667 /* we have physically contiguous memory mapped through PCI BAR */ 2668 poolofs = nm_os_pt_memdev_ioread(ptnmd->ptn_dev, 2669 PTNET_MDEV_IO_BUF_POOL_OFS); 2670 vaddr = (char *)(ptnmd->nm_addr) + poolofs; 2671 paddr = ptnmd->nm_paddr + poolofs; 2672 2673 for (i = 0; i < nbuffers; i++) { 2674 ptnmd->buf_lut.lut[i].vaddr = vaddr; 2675 vaddr += bufsize; 2676 paddr += bufsize; 2677 } 2678 2679 ptnmd->buf_lut.objtotal = nbuffers; 2680 ptnmd->buf_lut.objsize = bufsize; 2681 nmd->nm_totalsize = mem_size; 2682 2683 /* Initialize these fields as are needed by 2684 * netmap_mem_bufsize(). 2685 * XXX please improve this, why do we need this 2686 * replication? maybe we nmd->pools[] should no be 2687 * there for the guest allocator? */ 2688 nmd->pools[NETMAP_BUF_POOL]._objsize = bufsize; 2689 nmd->pools[NETMAP_BUF_POOL]._objtotal = nbuffers; 2690 2691 nmd->flags |= NETMAP_MEM_FINALIZED; 2692 out: 2693 return error; 2694 } 2695 2696 static void 2697 netmap_mem_pt_guest_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na) 2698 { 2699 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2700 2701 if (nmd->active == 1 && 2702 (nmd->flags & NETMAP_MEM_FINALIZED)) { 2703 nmd->flags &= ~NETMAP_MEM_FINALIZED; 2704 /* unmap ptnetmap-memdev memory */ 2705 if (ptnmd->ptn_dev) { 2706 nm_os_pt_memdev_iounmap(ptnmd->ptn_dev); 2707 } 2708 ptnmd->nm_addr = NULL; 2709 ptnmd->nm_paddr = 0; 2710 } 2711 } 2712 2713 static ssize_t 2714 netmap_mem_pt_guest_if_offset(struct netmap_mem_d *nmd, const void *vaddr) 2715 { 2716 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2717 2718 return (const char *)(vaddr) - (char *)(ptnmd->nm_addr); 2719 } 2720 2721 static void 2722 netmap_mem_pt_guest_delete(struct netmap_mem_d *nmd) 2723 { 2724 if (nmd == NULL) 2725 return; 2726 if (netmap_verbose) 2727 nm_prinf("deleting %p", nmd); 2728 if (nmd->active > 0) 2729 nm_prerr("bug: deleting mem allocator with active=%d!", nmd->active); 2730 if (netmap_verbose) 2731 nm_prinf("done deleting %p", nmd); 2732 NMA_LOCK_DESTROY(nmd); 2733 nm_os_free(nmd); 2734 } 2735 2736 static struct netmap_if * 2737 netmap_mem_pt_guest_if_new(struct netmap_mem_d *nmd, 2738 struct netmap_adapter *na, struct netmap_priv_d *priv) 2739 { 2740 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2741 struct mem_pt_if *ptif; 2742 struct netmap_if *nifp = NULL; 2743 2744 ptif = netmap_mem_pt_guest_ifp_lookup(nmd, na->ifp); 2745 if (ptif == NULL) { 2746 nm_prerr("interface %s is not in passthrough", na->name); 2747 goto out; 2748 } 2749 2750 nifp = (struct netmap_if *)((char *)(ptnmd->nm_addr) + 2751 ptif->nifp_offset); 2752 out: 2753 return nifp; 2754 } 2755 2756 static void 2757 netmap_mem_pt_guest_if_delete(struct netmap_mem_d * nmd, 2758 struct netmap_adapter *na, struct netmap_if *nifp) 2759 { 2760 struct mem_pt_if *ptif; 2761 2762 ptif = netmap_mem_pt_guest_ifp_lookup(nmd, na->ifp); 2763 if (ptif == NULL) { 2764 nm_prerr("interface %s is not in passthrough", na->name); 2765 } 2766 } 2767 2768 static int 2769 netmap_mem_pt_guest_rings_create(struct netmap_mem_d *nmd, 2770 struct netmap_adapter *na) 2771 { 2772 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2773 struct mem_pt_if *ptif; 2774 struct netmap_if *nifp; 2775 int i, error = -1; 2776 2777 ptif = netmap_mem_pt_guest_ifp_lookup(nmd, na->ifp); 2778 if (ptif == NULL) { 2779 nm_prerr("interface %s is not in passthrough", na->name); 2780 goto out; 2781 } 2782 2783 2784 /* point each kring to the corresponding backend ring */ 2785 nifp = (struct netmap_if *)((char *)ptnmd->nm_addr + ptif->nifp_offset); 2786 for (i = 0; i < netmap_all_rings(na, NR_TX); i++) { 2787 struct netmap_kring *kring = na->tx_rings[i]; 2788 if (kring->ring) 2789 continue; 2790 kring->ring = (struct netmap_ring *) 2791 ((char *)nifp + nifp->ring_ofs[i]); 2792 } 2793 for (i = 0; i < netmap_all_rings(na, NR_RX); i++) { 2794 struct netmap_kring *kring = na->rx_rings[i]; 2795 if (kring->ring) 2796 continue; 2797 kring->ring = (struct netmap_ring *) 2798 ((char *)nifp + 2799 nifp->ring_ofs[netmap_all_rings(na, NR_TX) + i]); 2800 } 2801 2802 error = 0; 2803 out: 2804 return error; 2805 } 2806 2807 static void 2808 netmap_mem_pt_guest_rings_delete(struct netmap_mem_d *nmd, struct netmap_adapter *na) 2809 { 2810 #if 0 2811 enum txrx t; 2812 2813 for_rx_tx(t) { 2814 u_int i; 2815 for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { 2816 struct netmap_kring *kring = &NMR(na, t)[i]; 2817 2818 kring->ring = NULL; 2819 } 2820 } 2821 #endif 2822 (void)nmd; 2823 (void)na; 2824 } 2825 2826 static struct netmap_mem_ops netmap_mem_pt_guest_ops = { 2827 .nmd_get_lut = netmap_mem_pt_guest_get_lut, 2828 .nmd_get_info = netmap_mem_pt_guest_get_info, 2829 .nmd_ofstophys = netmap_mem_pt_guest_ofstophys, 2830 .nmd_config = netmap_mem_pt_guest_config, 2831 .nmd_finalize = netmap_mem_pt_guest_finalize, 2832 .nmd_deref = netmap_mem_pt_guest_deref, 2833 .nmd_if_offset = netmap_mem_pt_guest_if_offset, 2834 .nmd_delete = netmap_mem_pt_guest_delete, 2835 .nmd_if_new = netmap_mem_pt_guest_if_new, 2836 .nmd_if_delete = netmap_mem_pt_guest_if_delete, 2837 .nmd_rings_create = netmap_mem_pt_guest_rings_create, 2838 .nmd_rings_delete = netmap_mem_pt_guest_rings_delete 2839 }; 2840 2841 /* Called with nm_mem_list_lock held. */ 2842 static struct netmap_mem_d * 2843 netmap_mem_pt_guest_find_memid(nm_memid_t mem_id) 2844 { 2845 struct netmap_mem_d *mem = NULL; 2846 struct netmap_mem_d *scan = netmap_last_mem_d; 2847 2848 do { 2849 /* find ptnetmap allocator through host ID */ 2850 if (scan->ops->nmd_deref == netmap_mem_pt_guest_deref && 2851 ((struct netmap_mem_ptg *)(scan))->host_mem_id == mem_id) { 2852 mem = scan; 2853 mem->refcount++; 2854 NM_DBG_REFC(mem, __FUNCTION__, __LINE__); 2855 break; 2856 } 2857 scan = scan->next; 2858 } while (scan != netmap_last_mem_d); 2859 2860 return mem; 2861 } 2862 2863 /* Called with nm_mem_list_lock held. */ 2864 static struct netmap_mem_d * 2865 netmap_mem_pt_guest_create(nm_memid_t mem_id) 2866 { 2867 struct netmap_mem_ptg *ptnmd; 2868 int err = 0; 2869 2870 ptnmd = nm_os_malloc(sizeof(struct netmap_mem_ptg)); 2871 if (ptnmd == NULL) { 2872 err = ENOMEM; 2873 goto error; 2874 } 2875 2876 ptnmd->up.ops = &netmap_mem_pt_guest_ops; 2877 ptnmd->host_mem_id = mem_id; 2878 ptnmd->pt_ifs = NULL; 2879 2880 /* Assign new id in the guest (We have the lock) */ 2881 err = nm_mem_assign_id_locked(&ptnmd->up, -1); 2882 if (err) 2883 goto error; 2884 2885 ptnmd->up.flags &= ~NETMAP_MEM_FINALIZED; 2886 ptnmd->up.flags |= NETMAP_MEM_IO; 2887 2888 NMA_LOCK_INIT(&ptnmd->up); 2889 2890 snprintf(ptnmd->up.name, NM_MEM_NAMESZ, "%d", ptnmd->up.nm_id); 2891 2892 2893 return &ptnmd->up; 2894 error: 2895 netmap_mem_pt_guest_delete(&ptnmd->up); 2896 return NULL; 2897 } 2898 2899 /* 2900 * find host id in guest allocators and create guest allocator 2901 * if it is not there 2902 */ 2903 static struct netmap_mem_d * 2904 netmap_mem_pt_guest_get(nm_memid_t mem_id) 2905 { 2906 struct netmap_mem_d *nmd; 2907 2908 NM_MTX_LOCK(nm_mem_list_lock); 2909 nmd = netmap_mem_pt_guest_find_memid(mem_id); 2910 if (nmd == NULL) { 2911 nmd = netmap_mem_pt_guest_create(mem_id); 2912 } 2913 NM_MTX_UNLOCK(nm_mem_list_lock); 2914 2915 return nmd; 2916 } 2917 2918 /* 2919 * The guest allocator can be created by ptnetmap_memdev (during the device 2920 * attach) or by ptnetmap device (ptnet), during the netmap_attach. 2921 * 2922 * The order is not important (we have different order in LINUX and FreeBSD). 2923 * The first one, creates the device, and the second one simply attaches it. 2924 */ 2925 2926 /* Called when ptnetmap_memdev is attaching, to attach a new allocator in 2927 * the guest */ 2928 struct netmap_mem_d * 2929 netmap_mem_pt_guest_attach(struct ptnetmap_memdev *ptn_dev, nm_memid_t mem_id) 2930 { 2931 struct netmap_mem_d *nmd; 2932 struct netmap_mem_ptg *ptnmd; 2933 2934 nmd = netmap_mem_pt_guest_get(mem_id); 2935 2936 /* assign this device to the guest allocator */ 2937 if (nmd) { 2938 ptnmd = (struct netmap_mem_ptg *)nmd; 2939 ptnmd->ptn_dev = ptn_dev; 2940 } 2941 2942 return nmd; 2943 } 2944 2945 /* Called when ptnet device is attaching */ 2946 struct netmap_mem_d * 2947 netmap_mem_pt_guest_new(if_t ifp, 2948 unsigned int nifp_offset, 2949 unsigned int memid) 2950 { 2951 struct netmap_mem_d *nmd; 2952 2953 if (ifp == NULL) { 2954 return NULL; 2955 } 2956 2957 nmd = netmap_mem_pt_guest_get((nm_memid_t)memid); 2958 2959 if (nmd) { 2960 netmap_mem_pt_guest_ifp_add(nmd, ifp, nifp_offset); 2961 } 2962 2963 return nmd; 2964 } 2965 2966 #endif /* WITH_PTNETMAP */ 2967