xref: /dragonfly/sys/net/netmap/netmap_mem2.c (revision f933b737)
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 
26785c7ee6SFranco Fichtner #include <sys/cdefs.h> /* prerequisite */
27785c7ee6SFranco 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 */
34785c7ee6SFranco Fichtner #include <sys/socket.h> /* sockaddrs */
35785c7ee6SFranco Fichtner #include <sys/sysctl.h>
36fb578518SFranco Fichtner #include <net/if.h>
37fb578518SFranco Fichtner #include <net/if_var.h>
38785c7ee6SFranco Fichtner #include <sys/bus.h>	/* bus_dmamap_* */
39ed9bd855SFranco Fichtner 
40*f933b737SSascha Wildner #include <net/netmap/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
netmap_mem_ofstophys(struct netmap_mem_d * nmd,vm_ooffset_t offset)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
netmap_mem_get_info(struct netmap_mem_d * nmd,u_int * size,u_int * memflags)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
netmap_obj_offset(struct netmap_obj_pool * p,const void * vaddr)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
netmap_mem_if_offset(struct netmap_mem_d * nmd,const void * addr)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 *
netmap_obj_malloc(struct netmap_obj_pool * p,u_int len,uint32_t * start,uint32_t * index)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
netmap_obj_free(struct netmap_obj_pool * p,uint32_t j)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
netmap_obj_free_va(struct netmap_obj_pool * p,void * vaddr)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
netmap_new_bufs(struct netmap_mem_d * nmd,struct netmap_slot * slot,u_int n)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
netmap_free_buf(struct netmap_mem_d * nmd,uint32_t i)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
netmap_reset_obj_allocator(struct netmap_obj_pool * p)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
netmap_destroy_obj_allocator(struct netmap_obj_pool * p)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
netmap_config_obj_allocator(struct netmap_obj_pool * p,u_int objtotal,u_int objsize)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
netmap_finalize_obj_allocator(struct netmap_obj_pool * p)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
netmap_memory_config_changed(struct netmap_mem_d * nmd)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
netmap_mem_reset_all(struct netmap_mem_d * nmd)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
netmap_mem_finalize_all(struct netmap_mem_d * nmd)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
netmap_mem_private_delete(struct netmap_mem_d * nmd)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
netmap_mem_private_config(struct netmap_mem_d * nmd)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
netmap_mem_private_finalize(struct netmap_mem_d * nmd)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
netmap_mem_private_deref(struct netmap_mem_d * nmd)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 *
netmap_mem_private_new(const char * name,u_int txr,u_int txd,u_int rxr,u_int rxd)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
netmap_mem_global_config(struct netmap_mem_d * nmd)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
netmap_mem_global_finalize(struct netmap_mem_d * nmd)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
netmap_mem_init(void)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
netmap_mem_fini(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
netmap_free_rings(struct netmap_adapter * na)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
netmap_mem_rings_create(struct netmap_adapter * na)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
netmap_mem_rings_delete(struct netmap_adapter * na)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 *
netmap_mem_if_new(const char * ifname,struct netmap_adapter * na)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
netmap_mem_if_delete(struct netmap_adapter * na,struct netmap_if * nifp)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
netmap_mem_global_deref(struct netmap_mem_d * nmd)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
netmap_mem_finalize(struct netmap_mem_d * nmd)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
netmap_mem_deref(struct netmap_mem_d * nmd)1112fb578518SFranco Fichtner netmap_mem_deref(struct netmap_mem_d *nmd)
1113fb578518SFranco Fichtner {
1114fb578518SFranco Fichtner 	return nmd->deref(nmd);
1115fb578518SFranco Fichtner }
1116