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