1fb578518SFranco Fichtner /* 2fb578518SFranco Fichtner * Copyright (C) 2012-2013 Matteo Landi, Luigi Rizzo, Giuseppe Lettieri. All rights reserved. 3fb578518SFranco Fichtner * 4fb578518SFranco Fichtner * Redistribution and use in source and binary forms, with or without 5fb578518SFranco Fichtner * modification, are permitted provided that the following conditions 6fb578518SFranco Fichtner * are met: 7fb578518SFranco Fichtner * 1. Redistributions of source code must retain the above copyright 8fb578518SFranco Fichtner * notice, this list of conditions and the following disclaimer. 9fb578518SFranco Fichtner * 2. Redistributions in binary form must reproduce the above copyright 10fb578518SFranco Fichtner * notice, this list of conditions and the following disclaimer in the 11fb578518SFranco Fichtner * documentation and/or other materials provided with the distribution. 12fb578518SFranco Fichtner * 13fb578518SFranco Fichtner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14fb578518SFranco Fichtner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15fb578518SFranco Fichtner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16fb578518SFranco Fichtner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17fb578518SFranco Fichtner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18fb578518SFranco Fichtner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19fb578518SFranco Fichtner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20fb578518SFranco Fichtner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21fb578518SFranco Fichtner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22fb578518SFranco Fichtner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23fb578518SFranco Fichtner * SUCH DAMAGE. 24fb578518SFranco Fichtner */ 25fb578518SFranco Fichtner 26*ed9bd855SFranco Fichtner /* __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 241723 2012-10-19 09:41:45Z glebius $"); */ 27fb578518SFranco Fichtner 28fb578518SFranco Fichtner #include <sys/types.h> 29fb578518SFranco Fichtner #include <sys/malloc.h> 30fb578518SFranco Fichtner #include <sys/proc.h> 31*ed9bd855SFranco Fichtner #include <sys/socket.h> /* sockaddrs */ 32*ed9bd855SFranco Fichtner #include <sys/sysctl.h> 33*ed9bd855SFranco Fichtner #include <sys/bus.h> /* bus_dmamap_* */ 34*ed9bd855SFranco Fichtner 35fb578518SFranco Fichtner #include <vm/vm.h> /* vtophys */ 36fb578518SFranco Fichtner #include <vm/pmap.h> /* vtophys */ 37*ed9bd855SFranco Fichtner 38fb578518SFranco Fichtner #include <net/if.h> 39fb578518SFranco Fichtner #include <net/if_var.h> 40fb578518SFranco Fichtner #include <net/vnet.h> 41fb578518SFranco Fichtner #include <net/netmap.h> 42*ed9bd855SFranco Fichtner 43*ed9bd855SFranco Fichtner #include "netmap_kern.h" 44fb578518SFranco Fichtner #include "netmap_mem2.h" 45fb578518SFranco Fichtner 46*ed9bd855SFranco Fichtner #define NMA_LOCK_INIT(n) lockinit(&(n)->nm_mtx, "netmap memory allocator lock", 0, 0) 47*ed9bd855SFranco Fichtner #define NMA_LOCK_DESTROY(n) lockuninit(&(n)->nm_mtx) 48*ed9bd855SFranco Fichtner #define NMA_LOCK(n) lockmgr(&(n)->nm_mtx, LK_EXCLUSIVE) 49*ed9bd855SFranco Fichtner #define NMA_UNLOCK(n) lockmgr(&(n)->nm_mtx, LK_RELEASE) 50fb578518SFranco Fichtner 51fb578518SFranco Fichtner struct netmap_obj_params netmap_params[NETMAP_POOLS_NR] = { 52fb578518SFranco Fichtner [NETMAP_IF_POOL] = { 53fb578518SFranco Fichtner .size = 1024, 54fb578518SFranco Fichtner .num = 100, 55fb578518SFranco Fichtner }, 56fb578518SFranco Fichtner [NETMAP_RING_POOL] = { 57fb578518SFranco Fichtner .size = 9*PAGE_SIZE, 58fb578518SFranco Fichtner .num = 200, 59fb578518SFranco Fichtner }, 60fb578518SFranco Fichtner [NETMAP_BUF_POOL] = { 61fb578518SFranco Fichtner .size = 2048, 62fb578518SFranco Fichtner .num = NETMAP_BUF_MAX_NUM, 63fb578518SFranco Fichtner }, 64fb578518SFranco Fichtner }; 65fb578518SFranco Fichtner 66fb578518SFranco Fichtner 67fb578518SFranco Fichtner /* 68fb578518SFranco Fichtner * nm_mem is the memory allocator used for all physical interfaces 69fb578518SFranco Fichtner * running in netmap mode. 70fb578518SFranco Fichtner * Virtual (VALE) ports will have each its own allocator. 71fb578518SFranco Fichtner */ 72fb578518SFranco Fichtner static int netmap_mem_global_config(struct netmap_mem_d *nmd); 73fb578518SFranco Fichtner static int netmap_mem_global_finalize(struct netmap_mem_d *nmd); 74fb578518SFranco Fichtner static void netmap_mem_global_deref(struct netmap_mem_d *nmd); 75fb578518SFranco Fichtner struct netmap_mem_d nm_mem = { /* Our memory allocator. */ 76fb578518SFranco Fichtner .pools = { 77fb578518SFranco Fichtner [NETMAP_IF_POOL] = { 78fb578518SFranco Fichtner .name = "netmap_if", 79fb578518SFranco Fichtner .objminsize = sizeof(struct netmap_if), 80fb578518SFranco Fichtner .objmaxsize = 4096, 81fb578518SFranco Fichtner .nummin = 10, /* don't be stingy */ 82fb578518SFranco Fichtner .nummax = 10000, /* XXX very large */ 83fb578518SFranco Fichtner }, 84fb578518SFranco Fichtner [NETMAP_RING_POOL] = { 85fb578518SFranco Fichtner .name = "netmap_ring", 86fb578518SFranco Fichtner .objminsize = sizeof(struct netmap_ring), 87fb578518SFranco Fichtner .objmaxsize = 32*PAGE_SIZE, 88fb578518SFranco Fichtner .nummin = 2, 89fb578518SFranco Fichtner .nummax = 1024, 90fb578518SFranco Fichtner }, 91fb578518SFranco Fichtner [NETMAP_BUF_POOL] = { 92fb578518SFranco Fichtner .name = "netmap_buf", 93fb578518SFranco Fichtner .objminsize = 64, 94fb578518SFranco Fichtner .objmaxsize = 65536, 95fb578518SFranco Fichtner .nummin = 4, 96fb578518SFranco Fichtner .nummax = 1000000, /* one million! */ 97fb578518SFranco Fichtner }, 98fb578518SFranco Fichtner }, 99fb578518SFranco Fichtner .config = netmap_mem_global_config, 100fb578518SFranco Fichtner .finalize = netmap_mem_global_finalize, 101fb578518SFranco Fichtner .deref = netmap_mem_global_deref, 102fb578518SFranco Fichtner }; 103fb578518SFranco Fichtner 104fb578518SFranco Fichtner 105fb578518SFranco Fichtner // XXX logically belongs to nm_mem 106fb578518SFranco Fichtner struct lut_entry *netmap_buffer_lut; /* exported */ 107fb578518SFranco Fichtner 108fb578518SFranco Fichtner /* blueprint for the private memory allocators */ 109fb578518SFranco Fichtner static int netmap_mem_private_config(struct netmap_mem_d *nmd); 110fb578518SFranco Fichtner static int netmap_mem_private_finalize(struct netmap_mem_d *nmd); 111fb578518SFranco Fichtner static void netmap_mem_private_deref(struct netmap_mem_d *nmd); 112fb578518SFranco Fichtner const struct netmap_mem_d nm_blueprint = { 113fb578518SFranco Fichtner .pools = { 114fb578518SFranco Fichtner [NETMAP_IF_POOL] = { 115fb578518SFranco Fichtner .name = "%s_if", 116fb578518SFranco Fichtner .objminsize = sizeof(struct netmap_if), 117fb578518SFranco Fichtner .objmaxsize = 4096, 118fb578518SFranco Fichtner .nummin = 1, 119fb578518SFranco Fichtner .nummax = 10, 120fb578518SFranco Fichtner }, 121fb578518SFranco Fichtner [NETMAP_RING_POOL] = { 122fb578518SFranco Fichtner .name = "%s_ring", 123fb578518SFranco Fichtner .objminsize = sizeof(struct netmap_ring), 124fb578518SFranco Fichtner .objmaxsize = 32*PAGE_SIZE, 125fb578518SFranco Fichtner .nummin = 2, 126fb578518SFranco Fichtner .nummax = 1024, 127fb578518SFranco Fichtner }, 128fb578518SFranco Fichtner [NETMAP_BUF_POOL] = { 129fb578518SFranco Fichtner .name = "%s_buf", 130fb578518SFranco Fichtner .objminsize = 64, 131fb578518SFranco Fichtner .objmaxsize = 65536, 132fb578518SFranco Fichtner .nummin = 4, 133fb578518SFranco Fichtner .nummax = 1000000, /* one million! */ 134fb578518SFranco Fichtner }, 135fb578518SFranco Fichtner }, 136fb578518SFranco Fichtner .config = netmap_mem_private_config, 137fb578518SFranco Fichtner .finalize = netmap_mem_private_finalize, 138fb578518SFranco Fichtner .deref = netmap_mem_private_deref, 139fb578518SFranco Fichtner 140fb578518SFranco Fichtner .flags = NETMAP_MEM_PRIVATE, 141fb578518SFranco Fichtner }; 142fb578518SFranco Fichtner 143fb578518SFranco Fichtner /* memory allocator related sysctls */ 144fb578518SFranco Fichtner 145fb578518SFranco Fichtner #define STRINGIFY(x) #x 146fb578518SFranco Fichtner 147fb578518SFranco Fichtner 148fb578518SFranco Fichtner #define DECLARE_SYSCTLS(id, name) \ 149fb578518SFranco Fichtner SYSCTL_INT(_dev_netmap, OID_AUTO, name##_size, \ 150fb578518SFranco Fichtner CTLFLAG_RW, &netmap_params[id].size, 0, "Requested size of netmap " STRINGIFY(name) "s"); \ 151fb578518SFranco Fichtner SYSCTL_INT(_dev_netmap, OID_AUTO, name##_curr_size, \ 152fb578518SFranco Fichtner CTLFLAG_RD, &nm_mem.pools[id]._objsize, 0, "Current size of netmap " STRINGIFY(name) "s"); \ 153fb578518SFranco Fichtner SYSCTL_INT(_dev_netmap, OID_AUTO, name##_num, \ 154fb578518SFranco Fichtner CTLFLAG_RW, &netmap_params[id].num, 0, "Requested number of netmap " STRINGIFY(name) "s"); \ 155fb578518SFranco Fichtner SYSCTL_INT(_dev_netmap, OID_AUTO, name##_curr_num, \ 156fb578518SFranco Fichtner CTLFLAG_RD, &nm_mem.pools[id].objtotal, 0, "Current number of netmap " STRINGIFY(name) "s") 157fb578518SFranco Fichtner 158fb578518SFranco Fichtner SYSCTL_DECL(_dev_netmap); 159fb578518SFranco Fichtner DECLARE_SYSCTLS(NETMAP_IF_POOL, if); 160fb578518SFranco Fichtner DECLARE_SYSCTLS(NETMAP_RING_POOL, ring); 161fb578518SFranco Fichtner DECLARE_SYSCTLS(NETMAP_BUF_POOL, buf); 162fb578518SFranco Fichtner 163fb578518SFranco Fichtner /* 164fb578518SFranco Fichtner * First, find the allocator that contains the requested offset, 165fb578518SFranco Fichtner * then locate the cluster through a lookup table. 166fb578518SFranco Fichtner */ 167fb578518SFranco Fichtner vm_paddr_t 168fb578518SFranco Fichtner netmap_mem_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset) 169fb578518SFranco Fichtner { 170fb578518SFranco Fichtner int i; 171fb578518SFranco Fichtner vm_ooffset_t o = offset; 172fb578518SFranco Fichtner vm_paddr_t pa; 173fb578518SFranco Fichtner struct netmap_obj_pool *p; 174fb578518SFranco Fichtner 175fb578518SFranco Fichtner NMA_LOCK(nmd); 176fb578518SFranco Fichtner p = nmd->pools; 177fb578518SFranco Fichtner 178fb578518SFranco Fichtner for (i = 0; i < NETMAP_POOLS_NR; offset -= p[i].memtotal, i++) { 179fb578518SFranco Fichtner if (offset >= p[i].memtotal) 180fb578518SFranco Fichtner continue; 181fb578518SFranco Fichtner // now lookup the cluster's address 182fb578518SFranco Fichtner pa = p[i].lut[offset / p[i]._objsize].paddr + 183fb578518SFranco Fichtner offset % p[i]._objsize; 184fb578518SFranco Fichtner NMA_UNLOCK(nmd); 185fb578518SFranco Fichtner return pa; 186fb578518SFranco Fichtner } 187fb578518SFranco Fichtner /* this is only in case of errors */ 188fb578518SFranco Fichtner D("invalid ofs 0x%x out of 0x%x 0x%x 0x%x", (u_int)o, 189fb578518SFranco Fichtner p[NETMAP_IF_POOL].memtotal, 190fb578518SFranco Fichtner p[NETMAP_IF_POOL].memtotal 191fb578518SFranco Fichtner + p[NETMAP_RING_POOL].memtotal, 192fb578518SFranco Fichtner p[NETMAP_IF_POOL].memtotal 193fb578518SFranco Fichtner + p[NETMAP_RING_POOL].memtotal 194fb578518SFranco Fichtner + p[NETMAP_BUF_POOL].memtotal); 195fb578518SFranco Fichtner NMA_UNLOCK(nmd); 196fb578518SFranco Fichtner return 0; // XXX bad address 197fb578518SFranco Fichtner } 198fb578518SFranco Fichtner 199fb578518SFranco Fichtner int 200fb578518SFranco Fichtner netmap_mem_get_info(struct netmap_mem_d* nmd, u_int* size, u_int *memflags) 201fb578518SFranco Fichtner { 202fb578518SFranco Fichtner int error = 0; 203fb578518SFranco Fichtner NMA_LOCK(nmd); 204fb578518SFranco Fichtner error = nmd->config(nmd); 205fb578518SFranco Fichtner if (error) 206fb578518SFranco Fichtner goto out; 207fb578518SFranco Fichtner if (nmd->flags & NETMAP_MEM_FINALIZED) { 208fb578518SFranco Fichtner *size = nmd->nm_totalsize; 209fb578518SFranco Fichtner } else { 210fb578518SFranco Fichtner int i; 211fb578518SFranco Fichtner *size = 0; 212fb578518SFranco Fichtner for (i = 0; i < NETMAP_POOLS_NR; i++) { 213fb578518SFranco Fichtner struct netmap_obj_pool *p = nmd->pools + i; 214fb578518SFranco Fichtner *size += (p->_numclusters * p->_clustsize); 215fb578518SFranco Fichtner } 216fb578518SFranco Fichtner } 217fb578518SFranco Fichtner *memflags = nmd->flags; 218fb578518SFranco Fichtner out: 219fb578518SFranco Fichtner NMA_UNLOCK(nmd); 220fb578518SFranco Fichtner return error; 221fb578518SFranco Fichtner } 222fb578518SFranco Fichtner 223fb578518SFranco Fichtner /* 224fb578518SFranco Fichtner * we store objects by kernel address, need to find the offset 225fb578518SFranco Fichtner * within the pool to export the value to userspace. 226fb578518SFranco Fichtner * Algorithm: scan until we find the cluster, then add the 227fb578518SFranco Fichtner * actual offset in the cluster 228fb578518SFranco Fichtner */ 229fb578518SFranco Fichtner static ssize_t 230fb578518SFranco Fichtner netmap_obj_offset(struct netmap_obj_pool *p, const void *vaddr) 231fb578518SFranco Fichtner { 232fb578518SFranco Fichtner int i, k = p->_clustentries, n = p->objtotal; 233fb578518SFranco Fichtner ssize_t ofs = 0; 234fb578518SFranco Fichtner 235fb578518SFranco Fichtner for (i = 0; i < n; i += k, ofs += p->_clustsize) { 236fb578518SFranco Fichtner const char *base = p->lut[i].vaddr; 237fb578518SFranco Fichtner ssize_t relofs = (const char *) vaddr - base; 238fb578518SFranco Fichtner 239fb578518SFranco Fichtner if (relofs < 0 || relofs >= p->_clustsize) 240fb578518SFranco Fichtner continue; 241fb578518SFranco Fichtner 242fb578518SFranco Fichtner ofs = ofs + relofs; 243fb578518SFranco Fichtner ND("%s: return offset %d (cluster %d) for pointer %p", 244fb578518SFranco Fichtner p->name, ofs, i, vaddr); 245fb578518SFranco Fichtner return ofs; 246fb578518SFranco Fichtner } 247fb578518SFranco Fichtner D("address %p is not contained inside any cluster (%s)", 248fb578518SFranco Fichtner vaddr, p->name); 249fb578518SFranco Fichtner return 0; /* An error occurred */ 250fb578518SFranco Fichtner } 251fb578518SFranco Fichtner 252fb578518SFranco Fichtner /* Helper functions which convert virtual addresses to offsets */ 253fb578518SFranco Fichtner #define netmap_if_offset(n, v) \ 254fb578518SFranco Fichtner netmap_obj_offset(&(n)->pools[NETMAP_IF_POOL], (v)) 255fb578518SFranco Fichtner 256fb578518SFranco Fichtner #define netmap_ring_offset(n, v) \ 257fb578518SFranco Fichtner ((n)->pools[NETMAP_IF_POOL].memtotal + \ 258fb578518SFranco Fichtner netmap_obj_offset(&(n)->pools[NETMAP_RING_POOL], (v))) 259fb578518SFranco Fichtner 260fb578518SFranco Fichtner #define netmap_buf_offset(n, v) \ 261fb578518SFranco Fichtner ((n)->pools[NETMAP_IF_POOL].memtotal + \ 262fb578518SFranco Fichtner (n)->pools[NETMAP_RING_POOL].memtotal + \ 263fb578518SFranco Fichtner netmap_obj_offset(&(n)->pools[NETMAP_BUF_POOL], (v))) 264fb578518SFranco Fichtner 265fb578518SFranco Fichtner 266fb578518SFranco Fichtner ssize_t 267fb578518SFranco Fichtner netmap_mem_if_offset(struct netmap_mem_d *nmd, const void *addr) 268fb578518SFranco Fichtner { 269fb578518SFranco Fichtner ssize_t v; 270fb578518SFranco Fichtner NMA_LOCK(nmd); 271fb578518SFranco Fichtner v = netmap_if_offset(nmd, addr); 272fb578518SFranco Fichtner NMA_UNLOCK(nmd); 273fb578518SFranco Fichtner return v; 274fb578518SFranco Fichtner } 275fb578518SFranco Fichtner 276fb578518SFranco Fichtner /* 277fb578518SFranco Fichtner * report the index, and use start position as a hint, 278fb578518SFranco Fichtner * otherwise buffer allocation becomes terribly expensive. 279fb578518SFranco Fichtner */ 280fb578518SFranco Fichtner static void * 281fb578518SFranco Fichtner netmap_obj_malloc(struct netmap_obj_pool *p, u_int len, uint32_t *start, uint32_t *index) 282fb578518SFranco Fichtner { 283fb578518SFranco Fichtner uint32_t i = 0; /* index in the bitmap */ 284fb578518SFranco Fichtner uint32_t mask, j; /* slot counter */ 285fb578518SFranco Fichtner void *vaddr = NULL; 286fb578518SFranco Fichtner 287fb578518SFranco Fichtner if (len > p->_objsize) { 288fb578518SFranco Fichtner D("%s request size %d too large", p->name, len); 289fb578518SFranco Fichtner // XXX cannot reduce the size 290fb578518SFranco Fichtner return NULL; 291fb578518SFranco Fichtner } 292fb578518SFranco Fichtner 293fb578518SFranco Fichtner if (p->objfree == 0) { 294fb578518SFranco Fichtner D("%s allocator: run out of memory", p->name); 295fb578518SFranco Fichtner return NULL; 296fb578518SFranco Fichtner } 297fb578518SFranco Fichtner if (start) 298fb578518SFranco Fichtner i = *start; 299fb578518SFranco Fichtner 300fb578518SFranco Fichtner /* termination is guaranteed by p->free, but better check bounds on i */ 301fb578518SFranco Fichtner while (vaddr == NULL && i < p->bitmap_slots) { 302fb578518SFranco Fichtner uint32_t cur = p->bitmap[i]; 303fb578518SFranco Fichtner if (cur == 0) { /* bitmask is fully used */ 304fb578518SFranco Fichtner i++; 305fb578518SFranco Fichtner continue; 306fb578518SFranco Fichtner } 307fb578518SFranco Fichtner /* locate a slot */ 308fb578518SFranco Fichtner for (j = 0, mask = 1; (cur & mask) == 0; j++, mask <<= 1) 309fb578518SFranco Fichtner ; 310fb578518SFranco Fichtner 311fb578518SFranco Fichtner p->bitmap[i] &= ~mask; /* mark object as in use */ 312fb578518SFranco Fichtner p->objfree--; 313fb578518SFranco Fichtner 314fb578518SFranco Fichtner vaddr = p->lut[i * 32 + j].vaddr; 315fb578518SFranco Fichtner if (index) 316fb578518SFranco Fichtner *index = i * 32 + j; 317fb578518SFranco Fichtner } 318fb578518SFranco Fichtner ND("%s allocator: allocated object @ [%d][%d]: vaddr %p", i, j, vaddr); 319fb578518SFranco Fichtner 320fb578518SFranco Fichtner if (start) 321fb578518SFranco Fichtner *start = i; 322fb578518SFranco Fichtner return vaddr; 323fb578518SFranco Fichtner } 324fb578518SFranco Fichtner 325fb578518SFranco Fichtner 326fb578518SFranco Fichtner /* 327fb578518SFranco Fichtner * free by index, not by address. This is slow, but is only used 328fb578518SFranco Fichtner * for a small number of objects (rings, nifp) 329fb578518SFranco Fichtner */ 330fb578518SFranco Fichtner static void 331fb578518SFranco Fichtner netmap_obj_free(struct netmap_obj_pool *p, uint32_t j) 332fb578518SFranco Fichtner { 333fb578518SFranco Fichtner if (j >= p->objtotal) { 334fb578518SFranco Fichtner D("invalid index %u, max %u", j, p->objtotal); 335fb578518SFranco Fichtner return; 336fb578518SFranco Fichtner } 337fb578518SFranco Fichtner p->bitmap[j / 32] |= (1 << (j % 32)); 338fb578518SFranco Fichtner p->objfree++; 339fb578518SFranco Fichtner return; 340fb578518SFranco Fichtner } 341fb578518SFranco Fichtner 342fb578518SFranco Fichtner static void 343fb578518SFranco Fichtner netmap_obj_free_va(struct netmap_obj_pool *p, void *vaddr) 344fb578518SFranco Fichtner { 345fb578518SFranco Fichtner u_int i, j, n = p->numclusters; 346fb578518SFranco Fichtner 347fb578518SFranco Fichtner for (i = 0, j = 0; i < n; i++, j += p->_clustentries) { 348fb578518SFranco Fichtner void *base = p->lut[i * p->_clustentries].vaddr; 349fb578518SFranco Fichtner ssize_t relofs = (ssize_t) vaddr - (ssize_t) base; 350fb578518SFranco Fichtner 351fb578518SFranco Fichtner /* Given address, is out of the scope of the current cluster.*/ 352fb578518SFranco Fichtner if (vaddr < base || relofs >= p->_clustsize) 353fb578518SFranco Fichtner continue; 354fb578518SFranco Fichtner 355fb578518SFranco Fichtner j = j + relofs / p->_objsize; 356fb578518SFranco Fichtner /* KASSERT(j != 0, ("Cannot free object 0")); */ 357fb578518SFranco Fichtner netmap_obj_free(p, j); 358fb578518SFranco Fichtner return; 359fb578518SFranco Fichtner } 360fb578518SFranco Fichtner D("address %p is not contained inside any cluster (%s)", 361fb578518SFranco Fichtner vaddr, p->name); 362fb578518SFranco Fichtner } 363fb578518SFranco Fichtner 364fb578518SFranco Fichtner #define netmap_if_malloc(n, len) netmap_obj_malloc(&(n)->pools[NETMAP_IF_POOL], len, NULL, NULL) 365fb578518SFranco Fichtner #define netmap_if_free(n, v) netmap_obj_free_va(&(n)->pools[NETMAP_IF_POOL], (v)) 366fb578518SFranco Fichtner #define netmap_ring_malloc(n, len) netmap_obj_malloc(&(n)->pools[NETMAP_RING_POOL], len, NULL, NULL) 367fb578518SFranco Fichtner #define netmap_ring_free(n, v) netmap_obj_free_va(&(n)->pools[NETMAP_RING_POOL], (v)) 368fb578518SFranco Fichtner #define netmap_buf_malloc(n, _pos, _index) \ 369fb578518SFranco Fichtner netmap_obj_malloc(&(n)->pools[NETMAP_BUF_POOL], NETMAP_BDG_BUF_SIZE(n), _pos, _index) 370fb578518SFranco Fichtner 371fb578518SFranco Fichtner 372fb578518SFranco Fichtner /* Return the index associated to the given packet buffer */ 373fb578518SFranco Fichtner #define netmap_buf_index(n, v) \ 374fb578518SFranco Fichtner (netmap_obj_offset(&(n)->pools[NETMAP_BUF_POOL], (v)) / NETMAP_BDG_BUF_SIZE(n)) 375fb578518SFranco Fichtner 376fb578518SFranco Fichtner 377fb578518SFranco Fichtner /* Return nonzero on error */ 378fb578518SFranco Fichtner static int 379fb578518SFranco Fichtner netmap_new_bufs(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n) 380fb578518SFranco Fichtner { 381fb578518SFranco Fichtner struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL]; 382fb578518SFranco Fichtner u_int i = 0; /* slot counter */ 383fb578518SFranco Fichtner uint32_t pos = 0; /* slot in p->bitmap */ 384fb578518SFranco Fichtner uint32_t index = 0; /* buffer index */ 385fb578518SFranco Fichtner 386fb578518SFranco Fichtner for (i = 0; i < n; i++) { 387fb578518SFranco Fichtner void *vaddr = netmap_buf_malloc(nmd, &pos, &index); 388fb578518SFranco Fichtner if (vaddr == NULL) { 389fb578518SFranco Fichtner D("unable to locate empty packet buffer"); 390fb578518SFranco Fichtner goto cleanup; 391fb578518SFranco Fichtner } 392fb578518SFranco Fichtner slot[i].buf_idx = index; 393fb578518SFranco Fichtner slot[i].len = p->_objsize; 394fb578518SFranco Fichtner /* XXX setting flags=NS_BUF_CHANGED forces a pointer reload 395fb578518SFranco Fichtner * in the NIC ring. This is a hack that hides missing 396fb578518SFranco Fichtner * initializations in the drivers, and should go away. 397fb578518SFranco Fichtner */ 398fb578518SFranco Fichtner // slot[i].flags = NS_BUF_CHANGED; 399fb578518SFranco Fichtner } 400fb578518SFranco Fichtner 401fb578518SFranco Fichtner ND("allocated %d buffers, %d available, first at %d", n, p->objfree, pos); 402fb578518SFranco Fichtner return (0); 403fb578518SFranco Fichtner 404fb578518SFranco Fichtner cleanup: 405fb578518SFranco Fichtner while (i > 0) { 406fb578518SFranco Fichtner i--; 407fb578518SFranco Fichtner netmap_obj_free(p, slot[i].buf_idx); 408fb578518SFranco Fichtner } 409fb578518SFranco Fichtner bzero(slot, n * sizeof(slot[0])); 410fb578518SFranco Fichtner return (ENOMEM); 411fb578518SFranco Fichtner } 412fb578518SFranco Fichtner 413fb578518SFranco Fichtner 414fb578518SFranco Fichtner static void 415fb578518SFranco Fichtner netmap_free_buf(struct netmap_mem_d *nmd, uint32_t i) 416fb578518SFranco Fichtner { 417fb578518SFranco Fichtner struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL]; 418fb578518SFranco Fichtner 419fb578518SFranco Fichtner if (i < 2 || i >= p->objtotal) { 420fb578518SFranco Fichtner D("Cannot free buf#%d: should be in [2, %d[", i, p->objtotal); 421fb578518SFranco Fichtner return; 422fb578518SFranco Fichtner } 423fb578518SFranco Fichtner netmap_obj_free(p, i); 424fb578518SFranco Fichtner } 425fb578518SFranco Fichtner 426fb578518SFranco Fichtner static void 427fb578518SFranco Fichtner netmap_reset_obj_allocator(struct netmap_obj_pool *p) 428fb578518SFranco Fichtner { 429fb578518SFranco Fichtner 430fb578518SFranco Fichtner if (p == NULL) 431fb578518SFranco Fichtner return; 432fb578518SFranco Fichtner if (p->bitmap) 433*ed9bd855SFranco Fichtner kfree(p->bitmap, M_NETMAP); 434fb578518SFranco Fichtner p->bitmap = NULL; 435fb578518SFranco Fichtner if (p->lut) { 436fb578518SFranco Fichtner u_int i; 437fb578518SFranco Fichtner size_t sz = p->_clustsize; 438fb578518SFranco Fichtner 439fb578518SFranco Fichtner for (i = 0; i < p->objtotal; i += p->_clustentries) { 440fb578518SFranco Fichtner if (p->lut[i].vaddr) 441fb578518SFranco Fichtner contigfree(p->lut[i].vaddr, sz, M_NETMAP); 442fb578518SFranco Fichtner } 443fb578518SFranco Fichtner bzero(p->lut, sizeof(struct lut_entry) * p->objtotal); 444*ed9bd855SFranco Fichtner kfree(p->lut, M_NETMAP); 445fb578518SFranco Fichtner } 446fb578518SFranco Fichtner p->lut = NULL; 447fb578518SFranco Fichtner p->objtotal = 0; 448fb578518SFranco Fichtner p->memtotal = 0; 449fb578518SFranco Fichtner p->numclusters = 0; 450fb578518SFranco Fichtner p->objfree = 0; 451fb578518SFranco Fichtner } 452fb578518SFranco Fichtner 453fb578518SFranco Fichtner /* 454fb578518SFranco Fichtner * Free all resources related to an allocator. 455fb578518SFranco Fichtner */ 456fb578518SFranco Fichtner static void 457fb578518SFranco Fichtner netmap_destroy_obj_allocator(struct netmap_obj_pool *p) 458fb578518SFranco Fichtner { 459fb578518SFranco Fichtner if (p == NULL) 460fb578518SFranco Fichtner return; 461fb578518SFranco Fichtner netmap_reset_obj_allocator(p); 462fb578518SFranco Fichtner } 463fb578518SFranco Fichtner 464fb578518SFranco Fichtner /* 465fb578518SFranco Fichtner * We receive a request for objtotal objects, of size objsize each. 466fb578518SFranco Fichtner * Internally we may round up both numbers, as we allocate objects 467fb578518SFranco Fichtner * in small clusters multiple of the page size. 468fb578518SFranco Fichtner * We need to keep track of objtotal and clustentries, 469fb578518SFranco Fichtner * as they are needed when freeing memory. 470fb578518SFranco Fichtner * 471fb578518SFranco Fichtner * XXX note -- userspace needs the buffers to be contiguous, 472fb578518SFranco Fichtner * so we cannot afford gaps at the end of a cluster. 473fb578518SFranco Fichtner */ 474fb578518SFranco Fichtner 475fb578518SFranco Fichtner 476fb578518SFranco Fichtner /* call with NMA_LOCK held */ 477fb578518SFranco Fichtner static int 478fb578518SFranco Fichtner netmap_config_obj_allocator(struct netmap_obj_pool *p, u_int objtotal, u_int objsize) 479fb578518SFranco Fichtner { 480fb578518SFranco Fichtner int i; 481fb578518SFranco Fichtner u_int clustsize; /* the cluster size, multiple of page size */ 482fb578518SFranco Fichtner u_int clustentries; /* how many objects per entry */ 483fb578518SFranco Fichtner 484fb578518SFranco Fichtner /* we store the current request, so we can 485fb578518SFranco Fichtner * detect configuration changes later */ 486fb578518SFranco Fichtner p->r_objtotal = objtotal; 487fb578518SFranco Fichtner p->r_objsize = objsize; 488fb578518SFranco Fichtner 489fb578518SFranco Fichtner #define MAX_CLUSTSIZE (1<<17) 490fb578518SFranco Fichtner #define LINE_ROUND 64 491fb578518SFranco Fichtner if (objsize >= MAX_CLUSTSIZE) { 492fb578518SFranco Fichtner /* we could do it but there is no point */ 493fb578518SFranco Fichtner D("unsupported allocation for %d bytes", objsize); 494fb578518SFranco Fichtner return EINVAL; 495fb578518SFranco Fichtner } 496fb578518SFranco Fichtner /* make sure objsize is a multiple of LINE_ROUND */ 497fb578518SFranco Fichtner i = (objsize & (LINE_ROUND - 1)); 498fb578518SFranco Fichtner if (i) { 499fb578518SFranco Fichtner D("XXX aligning object by %d bytes", LINE_ROUND - i); 500fb578518SFranco Fichtner objsize += LINE_ROUND - i; 501fb578518SFranco Fichtner } 502fb578518SFranco Fichtner if (objsize < p->objminsize || objsize > p->objmaxsize) { 503fb578518SFranco Fichtner D("requested objsize %d out of range [%d, %d]", 504fb578518SFranco Fichtner objsize, p->objminsize, p->objmaxsize); 505fb578518SFranco Fichtner return EINVAL; 506fb578518SFranco Fichtner } 507fb578518SFranco Fichtner if (objtotal < p->nummin || objtotal > p->nummax) { 508fb578518SFranco Fichtner D("requested objtotal %d out of range [%d, %d]", 509fb578518SFranco Fichtner objtotal, p->nummin, p->nummax); 510fb578518SFranco Fichtner return EINVAL; 511fb578518SFranco Fichtner } 512fb578518SFranco Fichtner /* 513fb578518SFranco Fichtner * Compute number of objects using a brute-force approach: 514fb578518SFranco Fichtner * given a max cluster size, 515fb578518SFranco Fichtner * we try to fill it with objects keeping track of the 516fb578518SFranco Fichtner * wasted space to the next page boundary. 517fb578518SFranco Fichtner */ 518fb578518SFranco Fichtner for (clustentries = 0, i = 1;; i++) { 519fb578518SFranco Fichtner u_int delta, used = i * objsize; 520fb578518SFranco Fichtner if (used > MAX_CLUSTSIZE) 521fb578518SFranco Fichtner break; 522fb578518SFranco Fichtner delta = used % PAGE_SIZE; 523fb578518SFranco Fichtner if (delta == 0) { // exact solution 524fb578518SFranco Fichtner clustentries = i; 525fb578518SFranco Fichtner break; 526fb578518SFranco Fichtner } 527fb578518SFranco Fichtner if (delta > ( (clustentries*objsize) % PAGE_SIZE) ) 528fb578518SFranco Fichtner clustentries = i; 529fb578518SFranco Fichtner } 530fb578518SFranco Fichtner // D("XXX --- ouch, delta %d (bad for buffers)", delta); 531fb578518SFranco Fichtner /* compute clustsize and round to the next page */ 532fb578518SFranco Fichtner clustsize = clustentries * objsize; 533fb578518SFranco Fichtner i = (clustsize & (PAGE_SIZE - 1)); 534fb578518SFranco Fichtner if (i) 535fb578518SFranco Fichtner clustsize += PAGE_SIZE - i; 536fb578518SFranco Fichtner if (netmap_verbose) 537fb578518SFranco Fichtner D("objsize %d clustsize %d objects %d", 538fb578518SFranco Fichtner objsize, clustsize, clustentries); 539fb578518SFranco Fichtner 540fb578518SFranco Fichtner /* 541fb578518SFranco Fichtner * The number of clusters is n = ceil(objtotal/clustentries) 542fb578518SFranco Fichtner * objtotal' = n * clustentries 543fb578518SFranco Fichtner */ 544fb578518SFranco Fichtner p->_clustentries = clustentries; 545fb578518SFranco Fichtner p->_clustsize = clustsize; 546fb578518SFranco Fichtner p->_numclusters = (objtotal + clustentries - 1) / clustentries; 547fb578518SFranco Fichtner 548fb578518SFranco Fichtner /* actual values (may be larger than requested) */ 549fb578518SFranco Fichtner p->_objsize = objsize; 550fb578518SFranco Fichtner p->_objtotal = p->_numclusters * clustentries; 551fb578518SFranco Fichtner 552fb578518SFranco Fichtner return 0; 553fb578518SFranco Fichtner } 554fb578518SFranco Fichtner 555fb578518SFranco Fichtner 556fb578518SFranco Fichtner /* call with NMA_LOCK held */ 557fb578518SFranco Fichtner static int 558fb578518SFranco Fichtner netmap_finalize_obj_allocator(struct netmap_obj_pool *p) 559fb578518SFranco Fichtner { 560fb578518SFranco Fichtner int i; /* must be signed */ 561fb578518SFranco Fichtner size_t n; 562fb578518SFranco Fichtner 563fb578518SFranco Fichtner /* optimistically assume we have enough memory */ 564fb578518SFranco Fichtner p->numclusters = p->_numclusters; 565fb578518SFranco Fichtner p->objtotal = p->_objtotal; 566fb578518SFranco Fichtner 567fb578518SFranco Fichtner n = sizeof(struct lut_entry) * p->objtotal; 568*ed9bd855SFranco Fichtner p->lut = kmalloc(n, M_NETMAP, M_NOWAIT | M_ZERO); 569fb578518SFranco Fichtner if (p->lut == NULL) { 570fb578518SFranco Fichtner D("Unable to create lookup table (%d bytes) for '%s'", (int)n, p->name); 571fb578518SFranco Fichtner goto clean; 572fb578518SFranco Fichtner } 573fb578518SFranco Fichtner 574fb578518SFranco Fichtner /* Allocate the bitmap */ 575fb578518SFranco Fichtner n = (p->objtotal + 31) / 32; 576*ed9bd855SFranco Fichtner p->bitmap = kmalloc(sizeof(uint32_t) * n, M_NETMAP, M_NOWAIT | M_ZERO); 577fb578518SFranco Fichtner if (p->bitmap == NULL) { 578fb578518SFranco Fichtner D("Unable to create bitmap (%d entries) for allocator '%s'", (int)n, 579fb578518SFranco Fichtner p->name); 580fb578518SFranco Fichtner goto clean; 581fb578518SFranco Fichtner } 582fb578518SFranco Fichtner p->bitmap_slots = n; 583fb578518SFranco Fichtner 584fb578518SFranco Fichtner /* 585fb578518SFranco Fichtner * Allocate clusters, init pointers and bitmap 586fb578518SFranco Fichtner */ 587fb578518SFranco Fichtner 588fb578518SFranco Fichtner n = p->_clustsize; 589fb578518SFranco Fichtner for (i = 0; i < (int)p->objtotal;) { 590fb578518SFranco Fichtner int lim = i + p->_clustentries; 591fb578518SFranco Fichtner char *clust; 592fb578518SFranco Fichtner 593fb578518SFranco Fichtner clust = contigmalloc(n, M_NETMAP, M_NOWAIT | M_ZERO, 594fb578518SFranco Fichtner (size_t)0, -1UL, PAGE_SIZE, 0); 595fb578518SFranco Fichtner if (clust == NULL) { 596fb578518SFranco Fichtner /* 597fb578518SFranco Fichtner * If we get here, there is a severe memory shortage, 598fb578518SFranco Fichtner * so halve the allocated memory to reclaim some. 599fb578518SFranco Fichtner */ 600fb578518SFranco Fichtner D("Unable to create cluster at %d for '%s' allocator", 601fb578518SFranco Fichtner i, p->name); 602fb578518SFranco Fichtner if (i < 2) /* nothing to halve */ 603fb578518SFranco Fichtner goto out; 604fb578518SFranco Fichtner lim = i / 2; 605fb578518SFranco Fichtner for (i--; i >= lim; i--) { 606fb578518SFranco Fichtner p->bitmap[ (i>>5) ] &= ~( 1 << (i & 31) ); 607fb578518SFranco Fichtner if (i % p->_clustentries == 0 && p->lut[i].vaddr) 608fb578518SFranco Fichtner contigfree(p->lut[i].vaddr, 609fb578518SFranco Fichtner n, M_NETMAP); 610fb578518SFranco Fichtner } 611fb578518SFranco Fichtner out: 612fb578518SFranco Fichtner p->objtotal = i; 613fb578518SFranco Fichtner /* we may have stopped in the middle of a cluster */ 614fb578518SFranco Fichtner p->numclusters = (i + p->_clustentries - 1) / p->_clustentries; 615fb578518SFranco Fichtner break; 616fb578518SFranco Fichtner } 617fb578518SFranco Fichtner for (; i < lim; i++, clust += p->_objsize) { 618fb578518SFranco Fichtner p->bitmap[ (i>>5) ] |= ( 1 << (i & 31) ); 619fb578518SFranco Fichtner p->lut[i].vaddr = clust; 620fb578518SFranco Fichtner p->lut[i].paddr = vtophys(clust); 621fb578518SFranco Fichtner } 622fb578518SFranco Fichtner } 623fb578518SFranco Fichtner p->objfree = p->objtotal; 624fb578518SFranco Fichtner p->memtotal = p->numclusters * p->_clustsize; 625fb578518SFranco Fichtner if (p->objfree == 0) 626fb578518SFranco Fichtner goto clean; 627fb578518SFranco Fichtner if (netmap_verbose) 628fb578518SFranco Fichtner D("Pre-allocated %d clusters (%d/%dKB) for '%s'", 629fb578518SFranco Fichtner p->numclusters, p->_clustsize >> 10, 630fb578518SFranco Fichtner p->memtotal >> 10, p->name); 631fb578518SFranco Fichtner 632fb578518SFranco Fichtner return 0; 633fb578518SFranco Fichtner 634fb578518SFranco Fichtner clean: 635fb578518SFranco Fichtner netmap_reset_obj_allocator(p); 636fb578518SFranco Fichtner return ENOMEM; 637fb578518SFranco Fichtner } 638fb578518SFranco Fichtner 639fb578518SFranco Fichtner /* call with lock held */ 640fb578518SFranco Fichtner static int 641fb578518SFranco Fichtner netmap_memory_config_changed(struct netmap_mem_d *nmd) 642fb578518SFranco Fichtner { 643fb578518SFranco Fichtner int i; 644fb578518SFranco Fichtner 645fb578518SFranco Fichtner for (i = 0; i < NETMAP_POOLS_NR; i++) { 646fb578518SFranco Fichtner if (nmd->pools[i].r_objsize != netmap_params[i].size || 647fb578518SFranco Fichtner nmd->pools[i].r_objtotal != netmap_params[i].num) 648fb578518SFranco Fichtner return 1; 649fb578518SFranco Fichtner } 650fb578518SFranco Fichtner return 0; 651fb578518SFranco Fichtner } 652fb578518SFranco Fichtner 653fb578518SFranco Fichtner static void 654fb578518SFranco Fichtner netmap_mem_reset_all(struct netmap_mem_d *nmd) 655fb578518SFranco Fichtner { 656fb578518SFranco Fichtner int i; 657fb578518SFranco Fichtner D("resetting %p", nmd); 658fb578518SFranco Fichtner for (i = 0; i < NETMAP_POOLS_NR; i++) { 659fb578518SFranco Fichtner netmap_reset_obj_allocator(&nmd->pools[i]); 660fb578518SFranco Fichtner } 661fb578518SFranco Fichtner nmd->flags &= ~NETMAP_MEM_FINALIZED; 662fb578518SFranco Fichtner } 663fb578518SFranco Fichtner 664fb578518SFranco Fichtner static int 665fb578518SFranco Fichtner netmap_mem_finalize_all(struct netmap_mem_d *nmd) 666fb578518SFranco Fichtner { 667fb578518SFranco Fichtner int i; 668fb578518SFranco Fichtner if (nmd->flags & NETMAP_MEM_FINALIZED) 669fb578518SFranco Fichtner return 0; 670fb578518SFranco Fichtner nmd->lasterr = 0; 671fb578518SFranco Fichtner nmd->nm_totalsize = 0; 672fb578518SFranco Fichtner for (i = 0; i < NETMAP_POOLS_NR; i++) { 673fb578518SFranco Fichtner nmd->lasterr = netmap_finalize_obj_allocator(&nmd->pools[i]); 674fb578518SFranco Fichtner if (nmd->lasterr) 675fb578518SFranco Fichtner goto error; 676fb578518SFranco Fichtner nmd->nm_totalsize += nmd->pools[i].memtotal; 677fb578518SFranco Fichtner } 678fb578518SFranco Fichtner /* buffers 0 and 1 are reserved */ 679fb578518SFranco Fichtner nmd->pools[NETMAP_BUF_POOL].objfree -= 2; 680fb578518SFranco Fichtner nmd->pools[NETMAP_BUF_POOL].bitmap[0] = ~3; 681fb578518SFranco Fichtner nmd->flags |= NETMAP_MEM_FINALIZED; 682fb578518SFranco Fichtner 683fb578518SFranco Fichtner D("Have %d KB for interfaces, %d KB for rings and %d MB for buffers", 684fb578518SFranco Fichtner nmd->pools[NETMAP_IF_POOL].memtotal >> 10, 685fb578518SFranco Fichtner nmd->pools[NETMAP_RING_POOL].memtotal >> 10, 686fb578518SFranco Fichtner nmd->pools[NETMAP_BUF_POOL].memtotal >> 20); 687fb578518SFranco Fichtner 688fb578518SFranco Fichtner D("Free buffers: %d", nmd->pools[NETMAP_BUF_POOL].objfree); 689fb578518SFranco Fichtner 690fb578518SFranco Fichtner 691fb578518SFranco Fichtner return 0; 692fb578518SFranco Fichtner error: 693fb578518SFranco Fichtner netmap_mem_reset_all(nmd); 694fb578518SFranco Fichtner return nmd->lasterr; 695fb578518SFranco Fichtner } 696fb578518SFranco Fichtner 697fb578518SFranco Fichtner 698fb578518SFranco Fichtner 699fb578518SFranco Fichtner void 700fb578518SFranco Fichtner netmap_mem_private_delete(struct netmap_mem_d *nmd) 701fb578518SFranco Fichtner { 702fb578518SFranco Fichtner if (nmd == NULL) 703fb578518SFranco Fichtner return; 704fb578518SFranco Fichtner D("deleting %p", nmd); 705fb578518SFranco Fichtner if (nmd->refcount > 0) 706fb578518SFranco Fichtner D("bug: deleting mem allocator with refcount=%d!", nmd->refcount); 707fb578518SFranco Fichtner D("done deleting %p", nmd); 708fb578518SFranco Fichtner NMA_LOCK_DESTROY(nmd); 709*ed9bd855SFranco Fichtner kfree(nmd, M_DEVBUF); 710fb578518SFranco Fichtner } 711fb578518SFranco Fichtner 712fb578518SFranco Fichtner static int 713fb578518SFranco Fichtner netmap_mem_private_config(struct netmap_mem_d *nmd) 714fb578518SFranco Fichtner { 715fb578518SFranco Fichtner /* nothing to do, we are configured on creation 716fb578518SFranco Fichtner * and configuration never changes thereafter 717fb578518SFranco Fichtner */ 718fb578518SFranco Fichtner return 0; 719fb578518SFranco Fichtner } 720fb578518SFranco Fichtner 721fb578518SFranco Fichtner static int 722fb578518SFranco Fichtner netmap_mem_private_finalize(struct netmap_mem_d *nmd) 723fb578518SFranco Fichtner { 724fb578518SFranco Fichtner int err; 725fb578518SFranco Fichtner NMA_LOCK(nmd); 726fb578518SFranco Fichtner nmd->refcount++; 727fb578518SFranco Fichtner err = netmap_mem_finalize_all(nmd); 728fb578518SFranco Fichtner NMA_UNLOCK(nmd); 729fb578518SFranco Fichtner return err; 730fb578518SFranco Fichtner 731fb578518SFranco Fichtner } 732fb578518SFranco Fichtner 733fb578518SFranco Fichtner static void 734fb578518SFranco Fichtner netmap_mem_private_deref(struct netmap_mem_d *nmd) 735fb578518SFranco Fichtner { 736fb578518SFranco Fichtner NMA_LOCK(nmd); 737fb578518SFranco Fichtner if (--nmd->refcount <= 0) 738fb578518SFranco Fichtner netmap_mem_reset_all(nmd); 739fb578518SFranco Fichtner NMA_UNLOCK(nmd); 740fb578518SFranco Fichtner } 741fb578518SFranco Fichtner 742fb578518SFranco Fichtner struct netmap_mem_d * 743fb578518SFranco Fichtner netmap_mem_private_new(const char *name, u_int txr, u_int txd, u_int rxr, u_int rxd) 744fb578518SFranco Fichtner { 745fb578518SFranco Fichtner struct netmap_mem_d *d = NULL; 746fb578518SFranco Fichtner struct netmap_obj_params p[NETMAP_POOLS_NR]; 747fb578518SFranco Fichtner int i; 748fb578518SFranco Fichtner u_int maxd; 749fb578518SFranco Fichtner 750*ed9bd855SFranco Fichtner d = kmalloc(sizeof(struct netmap_mem_d), 751fb578518SFranco Fichtner M_DEVBUF, M_NOWAIT | M_ZERO); 752fb578518SFranco Fichtner if (d == NULL) 753fb578518SFranco Fichtner return NULL; 754fb578518SFranco Fichtner 755fb578518SFranco Fichtner *d = nm_blueprint; 756fb578518SFranco Fichtner 757fb578518SFranco Fichtner /* XXX the rest of the code assumes the stack rings are alwasy present */ 758fb578518SFranco Fichtner txr++; 759fb578518SFranco Fichtner rxr++; 760fb578518SFranco Fichtner p[NETMAP_IF_POOL].size = sizeof(struct netmap_if) + 761fb578518SFranco Fichtner sizeof(ssize_t) * (txr + rxr); 762fb578518SFranco Fichtner p[NETMAP_IF_POOL].num = 2; 763fb578518SFranco Fichtner maxd = (txd > rxd) ? txd : rxd; 764fb578518SFranco Fichtner p[NETMAP_RING_POOL].size = sizeof(struct netmap_ring) + 765fb578518SFranco Fichtner sizeof(struct netmap_slot) * maxd; 766fb578518SFranco Fichtner p[NETMAP_RING_POOL].num = txr + rxr; 767fb578518SFranco Fichtner p[NETMAP_BUF_POOL].size = 2048; /* XXX find a way to let the user choose this */ 768fb578518SFranco Fichtner p[NETMAP_BUF_POOL].num = rxr * (rxd + 2) + txr * (txd + 2); 769fb578518SFranco Fichtner 770fb578518SFranco Fichtner D("req if %d*%d ring %d*%d buf %d*%d", 771fb578518SFranco Fichtner p[NETMAP_IF_POOL].num, 772fb578518SFranco Fichtner p[NETMAP_IF_POOL].size, 773fb578518SFranco Fichtner p[NETMAP_RING_POOL].num, 774fb578518SFranco Fichtner p[NETMAP_RING_POOL].size, 775fb578518SFranco Fichtner p[NETMAP_BUF_POOL].num, 776fb578518SFranco Fichtner p[NETMAP_BUF_POOL].size); 777fb578518SFranco Fichtner 778fb578518SFranco Fichtner for (i = 0; i < NETMAP_POOLS_NR; i++) { 779*ed9bd855SFranco Fichtner ksnprintf(d->pools[i].name, NETMAP_POOL_MAX_NAMSZ, 780fb578518SFranco Fichtner nm_blueprint.pools[i].name, 781fb578518SFranco Fichtner name); 782fb578518SFranco Fichtner if (netmap_config_obj_allocator(&d->pools[i], 783fb578518SFranco Fichtner p[i].num, p[i].size)) 784fb578518SFranco Fichtner goto error; 785fb578518SFranco Fichtner } 786fb578518SFranco Fichtner 787fb578518SFranco Fichtner d->flags &= ~NETMAP_MEM_FINALIZED; 788fb578518SFranco Fichtner 789fb578518SFranco Fichtner NMA_LOCK_INIT(d); 790fb578518SFranco Fichtner 791fb578518SFranco Fichtner return d; 792fb578518SFranco Fichtner error: 793fb578518SFranco Fichtner netmap_mem_private_delete(d); 794fb578518SFranco Fichtner return NULL; 795fb578518SFranco Fichtner } 796fb578518SFranco Fichtner 797fb578518SFranco Fichtner 798fb578518SFranco Fichtner /* call with lock held */ 799fb578518SFranco Fichtner static int 800fb578518SFranco Fichtner netmap_mem_global_config(struct netmap_mem_d *nmd) 801fb578518SFranco Fichtner { 802fb578518SFranco Fichtner int i; 803fb578518SFranco Fichtner 804fb578518SFranco Fichtner if (nmd->refcount) 805fb578518SFranco Fichtner /* already in use, we cannot change the configuration */ 806fb578518SFranco Fichtner goto out; 807fb578518SFranco Fichtner 808fb578518SFranco Fichtner if (!netmap_memory_config_changed(nmd)) 809fb578518SFranco Fichtner goto out; 810fb578518SFranco Fichtner 811fb578518SFranco Fichtner D("reconfiguring"); 812fb578518SFranco Fichtner 813fb578518SFranco Fichtner if (nmd->flags & NETMAP_MEM_FINALIZED) { 814fb578518SFranco Fichtner /* reset previous allocation */ 815fb578518SFranco Fichtner for (i = 0; i < NETMAP_POOLS_NR; i++) { 816fb578518SFranco Fichtner netmap_reset_obj_allocator(&nmd->pools[i]); 817fb578518SFranco Fichtner } 818fb578518SFranco Fichtner nmd->flags &= ~NETMAP_MEM_FINALIZED; 819fb578518SFranco Fichtner } 820fb578518SFranco Fichtner 821fb578518SFranco Fichtner for (i = 0; i < NETMAP_POOLS_NR; i++) { 822fb578518SFranco Fichtner nmd->lasterr = netmap_config_obj_allocator(&nmd->pools[i], 823fb578518SFranco Fichtner netmap_params[i].num, netmap_params[i].size); 824fb578518SFranco Fichtner if (nmd->lasterr) 825fb578518SFranco Fichtner goto out; 826fb578518SFranco Fichtner } 827fb578518SFranco Fichtner 828fb578518SFranco Fichtner out: 829fb578518SFranco Fichtner 830fb578518SFranco Fichtner return nmd->lasterr; 831fb578518SFranco Fichtner } 832fb578518SFranco Fichtner 833fb578518SFranco Fichtner static int 834fb578518SFranco Fichtner netmap_mem_global_finalize(struct netmap_mem_d *nmd) 835fb578518SFranco Fichtner { 836fb578518SFranco Fichtner int err; 837fb578518SFranco Fichtner 838fb578518SFranco Fichtner NMA_LOCK(nmd); 839fb578518SFranco Fichtner 840fb578518SFranco Fichtner 841fb578518SFranco Fichtner /* update configuration if changed */ 842fb578518SFranco Fichtner if (netmap_mem_global_config(nmd)) 843fb578518SFranco Fichtner goto out; 844fb578518SFranco Fichtner 845fb578518SFranco Fichtner nmd->refcount++; 846fb578518SFranco Fichtner 847fb578518SFranco Fichtner if (nmd->flags & NETMAP_MEM_FINALIZED) { 848fb578518SFranco Fichtner /* may happen if config is not changed */ 849fb578518SFranco Fichtner ND("nothing to do"); 850fb578518SFranco Fichtner goto out; 851fb578518SFranco Fichtner } 852fb578518SFranco Fichtner 853fb578518SFranco Fichtner if (netmap_mem_finalize_all(nmd)) 854fb578518SFranco Fichtner goto out; 855fb578518SFranco Fichtner 856fb578518SFranco Fichtner /* backward compatibility */ 857fb578518SFranco Fichtner netmap_buf_size = nmd->pools[NETMAP_BUF_POOL]._objsize; 858fb578518SFranco Fichtner netmap_total_buffers = nmd->pools[NETMAP_BUF_POOL].objtotal; 859fb578518SFranco Fichtner 860fb578518SFranco Fichtner netmap_buffer_lut = nmd->pools[NETMAP_BUF_POOL].lut; 861fb578518SFranco Fichtner netmap_buffer_base = nmd->pools[NETMAP_BUF_POOL].lut[0].vaddr; 862fb578518SFranco Fichtner 863fb578518SFranco Fichtner nmd->lasterr = 0; 864fb578518SFranco Fichtner 865fb578518SFranco Fichtner out: 866fb578518SFranco Fichtner if (nmd->lasterr) 867fb578518SFranco Fichtner nmd->refcount--; 868fb578518SFranco Fichtner err = nmd->lasterr; 869fb578518SFranco Fichtner 870fb578518SFranco Fichtner NMA_UNLOCK(nmd); 871fb578518SFranco Fichtner 872fb578518SFranco Fichtner return err; 873fb578518SFranco Fichtner 874fb578518SFranco Fichtner } 875fb578518SFranco Fichtner 876fb578518SFranco Fichtner int 877fb578518SFranco Fichtner netmap_mem_init(void) 878fb578518SFranco Fichtner { 879fb578518SFranco Fichtner NMA_LOCK_INIT(&nm_mem); 880fb578518SFranco Fichtner return (0); 881fb578518SFranco Fichtner } 882fb578518SFranco Fichtner 883fb578518SFranco Fichtner void 884fb578518SFranco Fichtner netmap_mem_fini(void) 885fb578518SFranco Fichtner { 886fb578518SFranco Fichtner int i; 887fb578518SFranco Fichtner 888fb578518SFranco Fichtner for (i = 0; i < NETMAP_POOLS_NR; i++) { 889fb578518SFranco Fichtner netmap_destroy_obj_allocator(&nm_mem.pools[i]); 890fb578518SFranco Fichtner } 891fb578518SFranco Fichtner NMA_LOCK_DESTROY(&nm_mem); 892fb578518SFranco Fichtner } 893fb578518SFranco Fichtner 894fb578518SFranco Fichtner static void 895fb578518SFranco Fichtner netmap_free_rings(struct netmap_adapter *na) 896fb578518SFranco Fichtner { 897fb578518SFranco Fichtner u_int i; 898fb578518SFranco Fichtner if (!na->tx_rings) 899fb578518SFranco Fichtner return; 900fb578518SFranco Fichtner for (i = 0; i < na->num_tx_rings + 1; i++) { 901fb578518SFranco Fichtner if (na->tx_rings[i].ring) { 902fb578518SFranco Fichtner netmap_ring_free(na->nm_mem, na->tx_rings[i].ring); 903fb578518SFranco Fichtner na->tx_rings[i].ring = NULL; 904fb578518SFranco Fichtner } 905fb578518SFranco Fichtner } 906fb578518SFranco Fichtner for (i = 0; i < na->num_rx_rings + 1; i++) { 907fb578518SFranco Fichtner if (na->rx_rings[i].ring) { 908fb578518SFranco Fichtner netmap_ring_free(na->nm_mem, na->rx_rings[i].ring); 909fb578518SFranco Fichtner na->rx_rings[i].ring = NULL; 910fb578518SFranco Fichtner } 911fb578518SFranco Fichtner } 912fb578518SFranco Fichtner } 913fb578518SFranco Fichtner 914fb578518SFranco Fichtner /* call with NMA_LOCK held * 915fb578518SFranco Fichtner * 916fb578518SFranco Fichtner * Allocate netmap rings and buffers for this card 917fb578518SFranco Fichtner * The rings are contiguous, but have variable size. 918fb578518SFranco Fichtner */ 919fb578518SFranco Fichtner int 920fb578518SFranco Fichtner netmap_mem_rings_create(struct netmap_adapter *na) 921fb578518SFranco Fichtner { 922fb578518SFranco Fichtner struct netmap_ring *ring; 923fb578518SFranco Fichtner u_int len, ndesc; 924fb578518SFranco Fichtner struct netmap_kring *kring; 925fb578518SFranco Fichtner 926fb578518SFranco Fichtner NMA_LOCK(na->nm_mem); 927fb578518SFranco Fichtner 928fb578518SFranco Fichtner for (kring = na->tx_rings; kring != na->rx_rings; kring++) { /* Transmit rings */ 929fb578518SFranco Fichtner ndesc = kring->nkr_num_slots; 930fb578518SFranco Fichtner len = sizeof(struct netmap_ring) + 931fb578518SFranco Fichtner ndesc * sizeof(struct netmap_slot); 932fb578518SFranco Fichtner ring = netmap_ring_malloc(na->nm_mem, len); 933fb578518SFranco Fichtner if (ring == NULL) { 934fb578518SFranco Fichtner D("Cannot allocate tx_ring"); 935fb578518SFranco Fichtner goto cleanup; 936fb578518SFranco Fichtner } 937fb578518SFranco Fichtner ND("txring[%d] at %p ofs %d", i, ring); 938fb578518SFranco Fichtner kring->ring = ring; 939fb578518SFranco Fichtner *(uint32_t *)(uintptr_t)&ring->num_slots = ndesc; 940fb578518SFranco Fichtner *(ssize_t *)(uintptr_t)&ring->buf_ofs = 941fb578518SFranco Fichtner (na->nm_mem->pools[NETMAP_IF_POOL].memtotal + 942fb578518SFranco Fichtner na->nm_mem->pools[NETMAP_RING_POOL].memtotal) - 943fb578518SFranco Fichtner netmap_ring_offset(na->nm_mem, ring); 944fb578518SFranco Fichtner 945fb578518SFranco Fichtner ring->avail = kring->nr_hwavail; 946fb578518SFranco Fichtner ring->cur = kring->nr_hwcur; 947fb578518SFranco Fichtner *(uint16_t *)(uintptr_t)&ring->nr_buf_size = 948fb578518SFranco Fichtner NETMAP_BDG_BUF_SIZE(na->nm_mem); 949fb578518SFranco Fichtner ND("initializing slots for txring"); 950fb578518SFranco Fichtner if (netmap_new_bufs(na->nm_mem, ring->slot, ndesc)) { 951fb578518SFranco Fichtner D("Cannot allocate buffers for tx_ring"); 952fb578518SFranco Fichtner goto cleanup; 953fb578518SFranco Fichtner } 954fb578518SFranco Fichtner } 955fb578518SFranco Fichtner 956fb578518SFranco Fichtner for ( ; kring != na->tailroom; kring++) { /* Receive rings */ 957fb578518SFranco Fichtner ndesc = kring->nkr_num_slots; 958fb578518SFranco Fichtner len = sizeof(struct netmap_ring) + 959fb578518SFranco Fichtner ndesc * sizeof(struct netmap_slot); 960fb578518SFranco Fichtner ring = netmap_ring_malloc(na->nm_mem, len); 961fb578518SFranco Fichtner if (ring == NULL) { 962fb578518SFranco Fichtner D("Cannot allocate rx_ring"); 963fb578518SFranco Fichtner goto cleanup; 964fb578518SFranco Fichtner } 965fb578518SFranco Fichtner ND("rxring at %p ofs %d", ring); 966fb578518SFranco Fichtner 967fb578518SFranco Fichtner kring->ring = ring; 968fb578518SFranco Fichtner *(uint32_t *)(uintptr_t)&ring->num_slots = ndesc; 969fb578518SFranco Fichtner *(ssize_t *)(uintptr_t)&ring->buf_ofs = 970fb578518SFranco Fichtner (na->nm_mem->pools[NETMAP_IF_POOL].memtotal + 971fb578518SFranco Fichtner na->nm_mem->pools[NETMAP_RING_POOL].memtotal) - 972fb578518SFranco Fichtner netmap_ring_offset(na->nm_mem, ring); 973fb578518SFranco Fichtner 974fb578518SFranco Fichtner ring->cur = kring->nr_hwcur; 975fb578518SFranco Fichtner ring->avail = kring->nr_hwavail; 976fb578518SFranco Fichtner *(int *)(uintptr_t)&ring->nr_buf_size = 977fb578518SFranco Fichtner NETMAP_BDG_BUF_SIZE(na->nm_mem); 978fb578518SFranco Fichtner ND("initializing slots for rxring[%d]", i); 979fb578518SFranco Fichtner if (netmap_new_bufs(na->nm_mem, ring->slot, ndesc)) { 980fb578518SFranco Fichtner D("Cannot allocate buffers for rx_ring"); 981fb578518SFranco Fichtner goto cleanup; 982fb578518SFranco Fichtner } 983fb578518SFranco Fichtner } 984fb578518SFranco Fichtner 985fb578518SFranco Fichtner NMA_UNLOCK(na->nm_mem); 986fb578518SFranco Fichtner 987fb578518SFranco Fichtner return 0; 988fb578518SFranco Fichtner 989fb578518SFranco Fichtner cleanup: 990fb578518SFranco Fichtner netmap_free_rings(na); 991fb578518SFranco Fichtner 992fb578518SFranco Fichtner NMA_UNLOCK(na->nm_mem); 993fb578518SFranco Fichtner 994fb578518SFranco Fichtner return ENOMEM; 995fb578518SFranco Fichtner } 996fb578518SFranco Fichtner 997fb578518SFranco Fichtner void 998fb578518SFranco Fichtner netmap_mem_rings_delete(struct netmap_adapter *na) 999fb578518SFranco Fichtner { 1000fb578518SFranco Fichtner /* last instance, release bufs and rings */ 1001fb578518SFranco Fichtner u_int i, lim; 1002fb578518SFranco Fichtner struct netmap_kring *kring; 1003fb578518SFranco Fichtner struct netmap_ring *ring; 1004fb578518SFranco Fichtner 1005fb578518SFranco Fichtner NMA_LOCK(na->nm_mem); 1006fb578518SFranco Fichtner 1007fb578518SFranco Fichtner for (kring = na->tx_rings; kring != na->tailroom; kring++) { 1008fb578518SFranco Fichtner ring = kring->ring; 1009fb578518SFranco Fichtner if (ring == NULL) 1010fb578518SFranco Fichtner continue; 1011fb578518SFranco Fichtner lim = kring->nkr_num_slots; 1012fb578518SFranco Fichtner for (i = 0; i < lim; i++) 1013fb578518SFranco Fichtner netmap_free_buf(na->nm_mem, ring->slot[i].buf_idx); 1014fb578518SFranco Fichtner } 1015fb578518SFranco Fichtner netmap_free_rings(na); 1016fb578518SFranco Fichtner 1017fb578518SFranco Fichtner NMA_UNLOCK(na->nm_mem); 1018fb578518SFranco Fichtner } 1019fb578518SFranco Fichtner 1020fb578518SFranco Fichtner 1021fb578518SFranco Fichtner /* call with NMA_LOCK held */ 1022fb578518SFranco Fichtner /* 1023fb578518SFranco Fichtner * Allocate the per-fd structure netmap_if. 1024fb578518SFranco Fichtner * 1025fb578518SFranco Fichtner * We assume that the configuration stored in na 1026fb578518SFranco Fichtner * (number of tx/rx rings and descs) does not change while 1027fb578518SFranco Fichtner * the interface is in netmap mode. 1028fb578518SFranco Fichtner */ 1029fb578518SFranco Fichtner struct netmap_if * 1030fb578518SFranco Fichtner netmap_mem_if_new(const char *ifname, struct netmap_adapter *na) 1031fb578518SFranco Fichtner { 1032fb578518SFranco Fichtner struct netmap_if *nifp; 1033fb578518SFranco Fichtner ssize_t base; /* handy for relative offsets between rings and nifp */ 1034fb578518SFranco Fichtner u_int i, len, ntx, nrx; 1035fb578518SFranco Fichtner 1036fb578518SFranco Fichtner /* 1037fb578518SFranco Fichtner * verify whether virtual port need the stack ring 1038fb578518SFranco Fichtner */ 1039fb578518SFranco Fichtner ntx = na->num_tx_rings + 1; /* shorthand, include stack ring */ 1040fb578518SFranco Fichtner nrx = na->num_rx_rings + 1; /* shorthand, include stack ring */ 1041fb578518SFranco Fichtner /* 1042fb578518SFranco Fichtner * the descriptor is followed inline by an array of offsets 1043fb578518SFranco Fichtner * to the tx and rx rings in the shared memory region. 1044fb578518SFranco Fichtner * For virtual rx rings we also allocate an array of 1045fb578518SFranco Fichtner * pointers to assign to nkr_leases. 1046fb578518SFranco Fichtner */ 1047fb578518SFranco Fichtner 1048fb578518SFranco Fichtner NMA_LOCK(na->nm_mem); 1049fb578518SFranco Fichtner 1050fb578518SFranco Fichtner len = sizeof(struct netmap_if) + (nrx + ntx) * sizeof(ssize_t); 1051fb578518SFranco Fichtner nifp = netmap_if_malloc(na->nm_mem, len); 1052fb578518SFranco Fichtner if (nifp == NULL) { 1053fb578518SFranco Fichtner NMA_UNLOCK(na->nm_mem); 1054fb578518SFranco Fichtner return NULL; 1055fb578518SFranco Fichtner } 1056fb578518SFranco Fichtner 1057fb578518SFranco Fichtner /* initialize base fields -- override const */ 1058fb578518SFranco Fichtner *(u_int *)(uintptr_t)&nifp->ni_tx_rings = na->num_tx_rings; 1059fb578518SFranco Fichtner *(u_int *)(uintptr_t)&nifp->ni_rx_rings = na->num_rx_rings; 1060fb578518SFranco Fichtner strncpy(nifp->ni_name, ifname, (size_t)IFNAMSIZ); 1061fb578518SFranco Fichtner 1062fb578518SFranco Fichtner /* 1063fb578518SFranco Fichtner * fill the slots for the rx and tx rings. They contain the offset 1064fb578518SFranco Fichtner * between the ring and nifp, so the information is usable in 1065fb578518SFranco Fichtner * userspace to reach the ring from the nifp. 1066fb578518SFranco Fichtner */ 1067fb578518SFranco Fichtner base = netmap_if_offset(na->nm_mem, nifp); 1068fb578518SFranco Fichtner for (i = 0; i < ntx; i++) { 1069fb578518SFranco Fichtner *(ssize_t *)(uintptr_t)&nifp->ring_ofs[i] = 1070fb578518SFranco Fichtner netmap_ring_offset(na->nm_mem, na->tx_rings[i].ring) - base; 1071fb578518SFranco Fichtner } 1072fb578518SFranco Fichtner for (i = 0; i < nrx; i++) { 1073fb578518SFranco Fichtner *(ssize_t *)(uintptr_t)&nifp->ring_ofs[i+ntx] = 1074fb578518SFranco Fichtner netmap_ring_offset(na->nm_mem, na->rx_rings[i].ring) - base; 1075fb578518SFranco Fichtner } 1076fb578518SFranco Fichtner 1077fb578518SFranco Fichtner NMA_UNLOCK(na->nm_mem); 1078fb578518SFranco Fichtner 1079fb578518SFranco Fichtner return (nifp); 1080fb578518SFranco Fichtner } 1081fb578518SFranco Fichtner 1082fb578518SFranco Fichtner void 1083fb578518SFranco Fichtner netmap_mem_if_delete(struct netmap_adapter *na, struct netmap_if *nifp) 1084fb578518SFranco Fichtner { 1085fb578518SFranco Fichtner if (nifp == NULL) 1086fb578518SFranco Fichtner /* nothing to do */ 1087fb578518SFranco Fichtner return; 1088fb578518SFranco Fichtner NMA_LOCK(na->nm_mem); 1089fb578518SFranco Fichtner 1090fb578518SFranco Fichtner netmap_if_free(na->nm_mem, nifp); 1091fb578518SFranco Fichtner 1092fb578518SFranco Fichtner NMA_UNLOCK(na->nm_mem); 1093fb578518SFranco Fichtner } 1094fb578518SFranco Fichtner 1095fb578518SFranco Fichtner static void 1096fb578518SFranco Fichtner netmap_mem_global_deref(struct netmap_mem_d *nmd) 1097fb578518SFranco Fichtner { 1098fb578518SFranco Fichtner NMA_LOCK(nmd); 1099fb578518SFranco Fichtner 1100fb578518SFranco Fichtner nmd->refcount--; 1101fb578518SFranco Fichtner if (netmap_verbose) 1102fb578518SFranco Fichtner D("refcount = %d", nmd->refcount); 1103fb578518SFranco Fichtner 1104fb578518SFranco Fichtner NMA_UNLOCK(nmd); 1105fb578518SFranco Fichtner } 1106fb578518SFranco Fichtner 1107fb578518SFranco Fichtner int 1108fb578518SFranco Fichtner netmap_mem_finalize(struct netmap_mem_d *nmd) 1109fb578518SFranco Fichtner { 1110fb578518SFranco Fichtner return nmd->finalize(nmd); 1111fb578518SFranco Fichtner } 1112fb578518SFranco Fichtner 1113fb578518SFranco Fichtner void 1114fb578518SFranco Fichtner netmap_mem_deref(struct netmap_mem_d *nmd) 1115fb578518SFranco Fichtner { 1116fb578518SFranco Fichtner return nmd->deref(nmd); 1117fb578518SFranco Fichtner } 1118