xref: /dragonfly/sys/net/netmap/netmap.c (revision f933b737)
1fb578518SFranco Fichtner /*
2fb578518SFranco Fichtner  * Copyright (C) 2011-2013 Matteo Landi, Luigi Rizzo. 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 
26fb578518SFranco Fichtner 
27fb578518SFranco Fichtner /*
28fb578518SFranco Fichtner  * This module supports memory mapped access to network devices,
29fb578518SFranco Fichtner  * see netmap(4).
30fb578518SFranco Fichtner  *
31fb578518SFranco Fichtner  * The module uses a large, memory pool allocated by the kernel
32fb578518SFranco Fichtner  * and accessible as mmapped memory by multiple userspace threads/processes.
33fb578518SFranco Fichtner  * The memory pool contains packet buffers and "netmap rings",
34fb578518SFranco Fichtner  * i.e. user-accessible copies of the interface's queues.
35fb578518SFranco Fichtner  *
36fb578518SFranco Fichtner  * Access to the network card works like this:
37fb578518SFranco Fichtner  * 1. a process/thread issues one or more open() on /dev/netmap, to create
38fb578518SFranco Fichtner  *    select()able file descriptor on which events are reported.
39fb578518SFranco Fichtner  * 2. on each descriptor, the process issues an ioctl() to identify
40fb578518SFranco Fichtner  *    the interface that should report events to the file descriptor.
41fb578518SFranco Fichtner  * 3. on each descriptor, the process issues an mmap() request to
42fb578518SFranco Fichtner  *    map the shared memory region within the process' address space.
43fb578518SFranco Fichtner  *    The list of interesting queues is indicated by a location in
44fb578518SFranco Fichtner  *    the shared memory region.
45fb578518SFranco Fichtner  * 4. using the functions in the netmap(4) userspace API, a process
46fb578518SFranco Fichtner  *    can look up the occupation state of a queue, access memory buffers,
47fb578518SFranco Fichtner  *    and retrieve received packets or enqueue packets to transmit.
48fb578518SFranco Fichtner  * 5. using some ioctl()s the process can synchronize the userspace view
49fb578518SFranco Fichtner  *    of the queue with the actual status in the kernel. This includes both
50fb578518SFranco Fichtner  *    receiving the notification of new packets, and transmitting new
51fb578518SFranco Fichtner  *    packets on the output interface.
52fb578518SFranco Fichtner  * 6. select() or poll() can be used to wait for events on individual
53fb578518SFranco Fichtner  *    transmit or receive queues (or all queues for a given interface).
54fb578518SFranco Fichtner  *
55fb578518SFranco Fichtner 
56fb578518SFranco Fichtner 		SYNCHRONIZATION (USER)
57fb578518SFranco Fichtner 
58fb578518SFranco Fichtner The netmap rings and data structures may be shared among multiple
59fb578518SFranco Fichtner user threads or even independent processes.
60fb578518SFranco Fichtner Any synchronization among those threads/processes is delegated
61fb578518SFranco Fichtner to the threads themselves. Only one thread at a time can be in
62fb578518SFranco Fichtner a system call on the same netmap ring. The OS does not enforce
63fb578518SFranco Fichtner this and only guarantees against system crashes in case of
64fb578518SFranco Fichtner invalid usage.
65fb578518SFranco Fichtner 
66fb578518SFranco Fichtner 		LOCKING (INTERNAL)
67fb578518SFranco Fichtner 
68fb578518SFranco Fichtner Within the kernel, access to the netmap rings is protected as follows:
69fb578518SFranco Fichtner 
70fb578518SFranco Fichtner - a spinlock on each ring, to handle producer/consumer races on
71fb578518SFranco Fichtner   RX rings attached to the host stack (against multiple host
72fb578518SFranco Fichtner   threads writing from the host stack to the same ring),
73fb578518SFranco Fichtner   and on 'destination' rings attached to a VALE switch
74fb578518SFranco Fichtner   (i.e. RX rings in VALE ports, and TX rings in NIC/host ports)
75fb578518SFranco Fichtner   protecting multiple active senders for the same destination)
76fb578518SFranco Fichtner 
77fb578518SFranco Fichtner - an atomic variable to guarantee that there is at most one
78fb578518SFranco Fichtner   instance of *_*xsync() on the ring at any time.
79fb578518SFranco Fichtner   For rings connected to user file
80fb578518SFranco Fichtner   descriptors, an atomic_test_and_set() protects this, and the
81fb578518SFranco Fichtner   lock on the ring is not actually used.
82fb578518SFranco Fichtner   For NIC RX rings connected to a VALE switch, an atomic_test_and_set()
83fb578518SFranco Fichtner   is also used to prevent multiple executions (the driver might indeed
84fb578518SFranco Fichtner   already guarantee this).
85fb578518SFranco Fichtner   For NIC TX rings connected to a VALE switch, the lock arbitrates
86fb578518SFranco Fichtner   access to the queue (both when allocating buffers and when pushing
87fb578518SFranco Fichtner   them out).
88fb578518SFranco Fichtner 
89fb578518SFranco Fichtner - *xsync() should be protected against initializations of the card.
90fb578518SFranco Fichtner   On FreeBSD most devices have the reset routine protected by
91fb578518SFranco Fichtner   a RING lock (ixgbe, igb, em) or core lock (re). lem is missing
92fb578518SFranco Fichtner   the RING protection on rx_reset(), this should be added.
93fb578518SFranco Fichtner 
94fb578518SFranco Fichtner   On linux there is an external lock on the tx path, which probably
95fb578518SFranco Fichtner   also arbitrates access to the reset routine. XXX to be revised
96fb578518SFranco Fichtner 
97fb578518SFranco Fichtner - a per-interface core_lock protecting access from the host stack
98fb578518SFranco Fichtner   while interfaces may be detached from netmap mode.
99fb578518SFranco Fichtner   XXX there should be no need for this lock if we detach the interfaces
100fb578518SFranco Fichtner   only while they are down.
101fb578518SFranco Fichtner 
102fb578518SFranco Fichtner 
103fb578518SFranco Fichtner --- VALE SWITCH ---
104fb578518SFranco Fichtner 
105fb578518SFranco Fichtner NMG_LOCK() serializes all modifications to switches and ports.
106fb578518SFranco Fichtner A switch cannot be deleted until all ports are gone.
107fb578518SFranco Fichtner 
108fb578518SFranco Fichtner For each switch, an SX lock (RWlock on linux) protects
109fb578518SFranco Fichtner deletion of ports. When configuring or deleting a new port, the
110fb578518SFranco Fichtner lock is acquired in exclusive mode (after holding NMG_LOCK).
111fb578518SFranco Fichtner When forwarding, the lock is acquired in shared mode (without NMG_LOCK).
112fb578518SFranco Fichtner The lock is held throughout the entire forwarding cycle,
113fb578518SFranco Fichtner during which the thread may incur in a page fault.
114fb578518SFranco Fichtner Hence it is important that sleepable shared locks are used.
115fb578518SFranco Fichtner 
116fb578518SFranco Fichtner On the rx ring, the per-port lock is grabbed initially to reserve
117fb578518SFranco Fichtner a number of slot in the ring, then the lock is released,
118fb578518SFranco Fichtner packets are copied from source to destination, and then
119fb578518SFranco Fichtner the lock is acquired again and the receive ring is updated.
120fb578518SFranco Fichtner (A similar thing is done on the tx ring for NIC and host stack
121fb578518SFranco Fichtner ports attached to the switch)
122fb578518SFranco Fichtner 
123fb578518SFranco Fichtner  */
124fb578518SFranco Fichtner 
125fb578518SFranco Fichtner /*
126fb578518SFranco Fichtner  * OS-specific code that is used only within this file.
127fb578518SFranco Fichtner  * Other OS-specific code that must be accessed by drivers
128fb578518SFranco Fichtner  * is present in netmap_kern.h
129fb578518SFranco Fichtner  */
130fb578518SFranco Fichtner 
131785c7ee6SFranco Fichtner #include <sys/cdefs.h> /* prerequisite */
132785c7ee6SFranco Fichtner __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z glebius $");
133785c7ee6SFranco Fichtner 
134fb578518SFranco Fichtner #include <sys/types.h>
135fb578518SFranco Fichtner #include <sys/errno.h>
136fb578518SFranco Fichtner #include <sys/param.h>	/* defines used in kernel.h */
137fb578518SFranco Fichtner #include <sys/kernel.h>	/* types used in module initialization */
138fb578518SFranco Fichtner #include <sys/conf.h>	/* cdevsw struct, UID, GID */
139bf9f7c16SFranco Fichtner #include <sys/devfs.h>
140fb578518SFranco Fichtner #include <sys/sockio.h>
141fb578518SFranco Fichtner #include <sys/socketvar.h>	/* struct socket */
142fb578518SFranco Fichtner #include <sys/malloc.h>
143fb578518SFranco Fichtner #include <sys/poll.h>
144ed9bd855SFranco Fichtner #include <sys/lock.h>
145fb578518SFranco Fichtner #include <sys/socket.h> /* sockaddrs */
14613431b3eSFranco Fichtner #include <sys/event.h>
147fb578518SFranco Fichtner #include <sys/sysctl.h>
148fb578518SFranco Fichtner #include <net/if.h>
149fb578518SFranco Fichtner #include <net/if_var.h>
150fb578518SFranco Fichtner #include <net/bpf.h>		/* BIOCIMMEDIATE */
15113431b3eSFranco Fichtner #include <sys/bus.h>	/* bus_dmamap_* */
15213431b3eSFranco Fichtner #include <sys/endian.h>
15313431b3eSFranco Fichtner #include <sys/refcount.h>
154fb578518SFranco Fichtner 
155fb578518SFranco Fichtner /* reduce conditional code */
156fb578518SFranco Fichtner #define init_waitqueue_head(x)	// only needed in linux
157fb578518SFranco Fichtner 
158bf9f7c16SFranco Fichtner extern struct dev_ops netmap_cdevsw;
159fb578518SFranco Fichtner 
160fb578518SFranco Fichtner /*
161fb578518SFranco Fichtner  * common headers
162fb578518SFranco Fichtner  */
163*f933b737SSascha Wildner #include <net/netmap/netmap.h>
164b3f97fadSFranco Fichtner #include <net/netmap/netmap_kern.h>
165b3f97fadSFranco Fichtner #include <net/netmap/netmap_mem2.h>
166fb578518SFranco Fichtner 
167785c7ee6SFranco Fichtner 
168fb578518SFranco Fichtner MALLOC_DEFINE(M_NETMAP, "netmap", "Network memory map");
169fb578518SFranco Fichtner 
170fb578518SFranco Fichtner /*
171fb578518SFranco Fichtner  * The following variables are used by the drivers and replicate
172fb578518SFranco Fichtner  * fields in the global memory pool. They only refer to buffers
173fb578518SFranco Fichtner  * used by physical interfaces.
174fb578518SFranco Fichtner  */
175fb578518SFranco Fichtner u_int netmap_total_buffers;
176fb578518SFranco Fichtner u_int netmap_buf_size;
177fb578518SFranco Fichtner char *netmap_buffer_base;	/* also address of an invalid buffer */
178fb578518SFranco Fichtner 
179fb578518SFranco Fichtner /* user-controlled variables */
180fb578518SFranco Fichtner int netmap_verbose;
181fb578518SFranco Fichtner 
182fb578518SFranco Fichtner static int netmap_no_timestamp; /* don't timestamp on rxsync */
183fb578518SFranco Fichtner 
18448b2c4afSSascha Wildner SYSCTL_NODE(_dev, OID_AUTO, netmap, CTLFLAG_RW, 0, "Netmap args");
18548b2c4afSSascha Wildner SYSCTL_INT(_dev_netmap, OID_AUTO, verbose,
186fb578518SFranco Fichtner     CTLFLAG_RW, &netmap_verbose, 0, "Verbose mode");
18748b2c4afSSascha Wildner SYSCTL_INT(_dev_netmap, OID_AUTO, no_timestamp,
188fb578518SFranco Fichtner     CTLFLAG_RW, &netmap_no_timestamp, 0, "no_timestamp");
189fb578518SFranco Fichtner int netmap_mitigate = 1;
19048b2c4afSSascha Wildner SYSCTL_INT(_dev_netmap, OID_AUTO, mitigate, CTLFLAG_RW, &netmap_mitigate, 0, "");
191fb578518SFranco Fichtner int netmap_no_pendintr = 1;
19248b2c4afSSascha Wildner SYSCTL_INT(_dev_netmap, OID_AUTO, no_pendintr,
193fb578518SFranco Fichtner     CTLFLAG_RW, &netmap_no_pendintr, 0, "Always look for new received packets.");
194fb578518SFranco Fichtner int netmap_txsync_retry = 2;
19548b2c4afSSascha Wildner SYSCTL_INT(_dev_netmap, OID_AUTO, txsync_retry, CTLFLAG_RW,
196fb578518SFranco Fichtner     &netmap_txsync_retry, 0 , "Number of txsync loops in bridge's flush.");
197fb578518SFranco Fichtner 
198fb578518SFranco Fichtner int netmap_flags = 0;	/* debug flags */
199fb578518SFranco Fichtner int netmap_fwd = 0;	/* force transparent mode */
200fb578518SFranco Fichtner int netmap_mmap_unreg = 0; /* allow mmap of unregistered fds */
201fb578518SFranco Fichtner 
202fb578518SFranco Fichtner /*
203fb578518SFranco Fichtner  * netmap_admode selects the netmap mode to use.
204fb578518SFranco Fichtner  * Invalid values are reset to NETMAP_ADMODE_BEST
205fb578518SFranco Fichtner  */
206fb578518SFranco Fichtner enum { NETMAP_ADMODE_BEST = 0,	/* use native, fallback to generic */
207fb578518SFranco Fichtner 	NETMAP_ADMODE_NATIVE,	/* either native or none */
208fb578518SFranco Fichtner 	NETMAP_ADMODE_GENERIC,	/* force generic */
209fb578518SFranco Fichtner 	NETMAP_ADMODE_LAST };
210fb578518SFranco Fichtner #define NETMAP_ADMODE_NATIVE        1  /* Force native netmap adapter. */
211fb578518SFranco Fichtner #define NETMAP_ADMODE_GENERIC       2  /* Force generic netmap adapter. */
212fb578518SFranco Fichtner #define NETMAP_ADMODE_BEST          0  /* Priority to native netmap adapter. */
213fb578518SFranco Fichtner static int netmap_admode = NETMAP_ADMODE_BEST;
214fb578518SFranco Fichtner 
215fb578518SFranco Fichtner int netmap_generic_mit = 100*1000;   /* Generic mitigation interval in nanoseconds. */
216fb578518SFranco Fichtner int netmap_generic_ringsize = 1024;   /* Generic ringsize. */
217fb578518SFranco Fichtner 
21848b2c4afSSascha Wildner SYSCTL_INT(_dev_netmap, OID_AUTO, flags, CTLFLAG_RW, &netmap_flags, 0 , "");
21948b2c4afSSascha Wildner SYSCTL_INT(_dev_netmap, OID_AUTO, fwd, CTLFLAG_RW, &netmap_fwd, 0 , "");
22048b2c4afSSascha Wildner SYSCTL_INT(_dev_netmap, OID_AUTO, mmap_unreg, CTLFLAG_RW, &netmap_mmap_unreg, 0, "");
22148b2c4afSSascha Wildner SYSCTL_INT(_dev_netmap, OID_AUTO, admode, CTLFLAG_RW, &netmap_admode, 0 , "");
22248b2c4afSSascha Wildner SYSCTL_INT(_dev_netmap, OID_AUTO, generic_mit, CTLFLAG_RW, &netmap_generic_mit, 0 , "");
22348b2c4afSSascha Wildner SYSCTL_INT(_dev_netmap, OID_AUTO, generic_ringsize, CTLFLAG_RW, &netmap_generic_ringsize, 0 , "");
224fb578518SFranco Fichtner 
225fb578518SFranco Fichtner NMG_LOCK_T	netmap_global_lock;
226fb578518SFranco Fichtner 
227fb578518SFranco Fichtner 
228fb578518SFranco Fichtner static void
nm_kr_get(struct netmap_kring * kr)229fb578518SFranco Fichtner nm_kr_get(struct netmap_kring *kr)
230fb578518SFranco Fichtner {
231fb578518SFranco Fichtner 	while (NM_ATOMIC_TEST_AND_SET(&kr->nr_busy))
232fb578518SFranco Fichtner 		tsleep(kr, 0, "NM_KR_GET", 4);
233fb578518SFranco Fichtner }
234fb578518SFranco Fichtner 
235fb578518SFranco Fichtner 
236fb578518SFranco Fichtner void
netmap_disable_ring(struct netmap_kring * kr)237fb578518SFranco Fichtner netmap_disable_ring(struct netmap_kring *kr)
238fb578518SFranco Fichtner {
239fb578518SFranco Fichtner 	kr->nkr_stopped = 1;
240fb578518SFranco Fichtner 	nm_kr_get(kr);
241ed9bd855SFranco Fichtner 	lockmgr(&kr->q_lock, LK_EXCLUSIVE);
242ed9bd855SFranco Fichtner 	lockmgr(&kr->q_lock, LK_RELEASE);
243fb578518SFranco Fichtner 	nm_kr_put(kr);
244fb578518SFranco Fichtner }
245fb578518SFranco Fichtner 
246fb578518SFranco Fichtner 
247fb578518SFranco Fichtner static void
netmap_set_all_rings(struct ifnet * ifp,int stopped)248fb578518SFranco Fichtner netmap_set_all_rings(struct ifnet *ifp, int stopped)
249fb578518SFranco Fichtner {
250fb578518SFranco Fichtner 	struct netmap_adapter *na;
251fb578518SFranco Fichtner 	int i;
252fb578518SFranco Fichtner 
253fb578518SFranco Fichtner 	if (!(ifp->if_capenable & IFCAP_NETMAP))
254fb578518SFranco Fichtner 		return;
255fb578518SFranco Fichtner 
256fb578518SFranco Fichtner 	na = NA(ifp);
257fb578518SFranco Fichtner 
258fb578518SFranco Fichtner 	for (i = 0; i <= na->num_tx_rings; i++) {
259fb578518SFranco Fichtner 		if (stopped)
260fb578518SFranco Fichtner 			netmap_disable_ring(na->tx_rings + i);
261fb578518SFranco Fichtner 		else
262fb578518SFranco Fichtner 			na->tx_rings[i].nkr_stopped = 0;
263fb578518SFranco Fichtner 		na->nm_notify(na, i, NR_TX, NAF_DISABLE_NOTIFY |
264fb578518SFranco Fichtner 			(i == na->num_tx_rings ? NAF_GLOBAL_NOTIFY: 0));
265fb578518SFranco Fichtner 	}
266fb578518SFranco Fichtner 
267fb578518SFranco Fichtner 	for (i = 0; i <= na->num_rx_rings; i++) {
268fb578518SFranco Fichtner 		if (stopped)
269fb578518SFranco Fichtner 			netmap_disable_ring(na->rx_rings + i);
270fb578518SFranco Fichtner 		else
271fb578518SFranco Fichtner 			na->rx_rings[i].nkr_stopped = 0;
272fb578518SFranco Fichtner 		na->nm_notify(na, i, NR_RX, NAF_DISABLE_NOTIFY |
273fb578518SFranco Fichtner 			(i == na->num_rx_rings ? NAF_GLOBAL_NOTIFY: 0));
274fb578518SFranco Fichtner 	}
275fb578518SFranco Fichtner }
276fb578518SFranco Fichtner 
277fb578518SFranco Fichtner 
278fb578518SFranco Fichtner void
netmap_disable_all_rings(struct ifnet * ifp)279fb578518SFranco Fichtner netmap_disable_all_rings(struct ifnet *ifp)
280fb578518SFranco Fichtner {
281fb578518SFranco Fichtner 	netmap_set_all_rings(ifp, 1 /* stopped */);
282fb578518SFranco Fichtner }
283fb578518SFranco Fichtner 
284fb578518SFranco Fichtner 
285fb578518SFranco Fichtner void
netmap_enable_all_rings(struct ifnet * ifp)286fb578518SFranco Fichtner netmap_enable_all_rings(struct ifnet *ifp)
287fb578518SFranco Fichtner {
288fb578518SFranco Fichtner 	netmap_set_all_rings(ifp, 0 /* enabled */);
289fb578518SFranco Fichtner }
290fb578518SFranco Fichtner 
291fb578518SFranco Fichtner 
292fb578518SFranco Fichtner /*
293fb578518SFranco Fichtner  * generic bound_checking function
294fb578518SFranco Fichtner  */
295fb578518SFranco Fichtner u_int
nm_bound_var(u_int * v,u_int dflt,u_int lo,u_int hi,const char * msg)296fb578518SFranco Fichtner nm_bound_var(u_int *v, u_int dflt, u_int lo, u_int hi, const char *msg)
297fb578518SFranco Fichtner {
298fb578518SFranco Fichtner 	u_int oldv = *v;
299fb578518SFranco Fichtner 	const char *op = NULL;
300fb578518SFranco Fichtner 
301fb578518SFranco Fichtner 	if (dflt < lo)
302fb578518SFranco Fichtner 		dflt = lo;
303fb578518SFranco Fichtner 	if (dflt > hi)
304fb578518SFranco Fichtner 		dflt = hi;
305fb578518SFranco Fichtner 	if (oldv < lo) {
306fb578518SFranco Fichtner 		*v = dflt;
307fb578518SFranco Fichtner 		op = "Bump";
308fb578518SFranco Fichtner 	} else if (oldv > hi) {
309fb578518SFranco Fichtner 		*v = hi;
310fb578518SFranco Fichtner 		op = "Clamp";
311fb578518SFranco Fichtner 	}
312fb578518SFranco Fichtner 	if (op && msg)
313ed9bd855SFranco Fichtner 		kprintf("%s %s to %d (was %d)\n", op, msg, *v, oldv);
314fb578518SFranco Fichtner 	return *v;
315fb578518SFranco Fichtner }
316fb578518SFranco Fichtner 
317fb578518SFranco Fichtner 
318fb578518SFranco Fichtner /*
319fb578518SFranco Fichtner  * packet-dump function, user-supplied or static buffer.
320fb578518SFranco Fichtner  * The destination buffer must be at least 30+4*len
321fb578518SFranco Fichtner  */
322fb578518SFranco Fichtner const char *
nm_dump_buf(char * p,int len,int lim,char * dst)323fb578518SFranco Fichtner nm_dump_buf(char *p, int len, int lim, char *dst)
324fb578518SFranco Fichtner {
325fb578518SFranco Fichtner 	static char _dst[8192];
326fb578518SFranco Fichtner 	int i, j, i0;
327fb578518SFranco Fichtner 	static char hex[] ="0123456789abcdef";
328fb578518SFranco Fichtner 	char *o;	/* output position */
329fb578518SFranco Fichtner 
330fb578518SFranco Fichtner #define P_HI(x)	hex[((x) & 0xf0)>>4]
331fb578518SFranco Fichtner #define P_LO(x)	hex[((x) & 0xf)]
332fb578518SFranco Fichtner #define P_C(x)	((x) >= 0x20 && (x) <= 0x7e ? (x) : '.')
333fb578518SFranco Fichtner 	if (!dst)
334fb578518SFranco Fichtner 		dst = _dst;
335fb578518SFranco Fichtner 	if (lim <= 0 || lim > len)
336fb578518SFranco Fichtner 		lim = len;
337fb578518SFranco Fichtner 	o = dst;
338ed9bd855SFranco Fichtner 	ksprintf(o, "buf 0x%p len %d lim %d\n", p, len, lim);
339fb578518SFranco Fichtner 	o += strlen(o);
340fb578518SFranco Fichtner 	/* hexdump routine */
341fb578518SFranco Fichtner 	for (i = 0; i < lim; ) {
342ed9bd855SFranco Fichtner 		ksprintf(o, "%5d: ", i);
343fb578518SFranco Fichtner 		o += strlen(o);
344fb578518SFranco Fichtner 		memset(o, ' ', 48);
345fb578518SFranco Fichtner 		i0 = i;
346fb578518SFranco Fichtner 		for (j=0; j < 16 && i < lim; i++, j++) {
347fb578518SFranco Fichtner 			o[j*3] = P_HI(p[i]);
348fb578518SFranco Fichtner 			o[j*3+1] = P_LO(p[i]);
349fb578518SFranco Fichtner 		}
350fb578518SFranco Fichtner 		i = i0;
351fb578518SFranco Fichtner 		for (j=0; j < 16 && i < lim; i++, j++)
352fb578518SFranco Fichtner 			o[j + 48] = P_C(p[i]);
353fb578518SFranco Fichtner 		o[j+48] = '\n';
354fb578518SFranco Fichtner 		o += j+49;
355fb578518SFranco Fichtner 	}
356fb578518SFranco Fichtner 	*o = '\0';
357fb578518SFranco Fichtner #undef P_HI
358fb578518SFranco Fichtner #undef P_LO
359fb578518SFranco Fichtner #undef P_C
360fb578518SFranco Fichtner 	return dst;
361fb578518SFranco Fichtner }
362fb578518SFranco Fichtner 
363fb578518SFranco Fichtner 
364fb578518SFranco Fichtner 
365fb578518SFranco Fichtner /*
366fb578518SFranco Fichtner  * Fetch configuration from the device, to cope with dynamic
367fb578518SFranco Fichtner  * reconfigurations after loading the module.
368fb578518SFranco Fichtner  */
369fb578518SFranco Fichtner int
netmap_update_config(struct netmap_adapter * na)370fb578518SFranco Fichtner netmap_update_config(struct netmap_adapter *na)
371fb578518SFranco Fichtner {
372fb578518SFranco Fichtner 	struct ifnet *ifp = na->ifp;
373fb578518SFranco Fichtner 	u_int txr, txd, rxr, rxd;
374fb578518SFranco Fichtner 
375fb578518SFranco Fichtner 	txr = txd = rxr = rxd = 0;
376fb578518SFranco Fichtner 	if (na->nm_config) {
377fb578518SFranco Fichtner 		na->nm_config(na, &txr, &txd, &rxr, &rxd);
378fb578518SFranco Fichtner 	} else {
379fb578518SFranco Fichtner 		/* take whatever we had at init time */
380fb578518SFranco Fichtner 		txr = na->num_tx_rings;
381fb578518SFranco Fichtner 		txd = na->num_tx_desc;
382fb578518SFranco Fichtner 		rxr = na->num_rx_rings;
383fb578518SFranco Fichtner 		rxd = na->num_rx_desc;
384fb578518SFranco Fichtner 	}
385fb578518SFranco Fichtner 
386fb578518SFranco Fichtner 	if (na->num_tx_rings == txr && na->num_tx_desc == txd &&
387fb578518SFranco Fichtner 	    na->num_rx_rings == rxr && na->num_rx_desc == rxd)
388fb578518SFranco Fichtner 		return 0; /* nothing changed */
389fb578518SFranco Fichtner 	if (netmap_verbose || na->active_fds > 0) {
390fb578518SFranco Fichtner 		D("stored config %s: txring %d x %d, rxring %d x %d",
391fb578518SFranco Fichtner 			NM_IFPNAME(ifp),
392fb578518SFranco Fichtner 			na->num_tx_rings, na->num_tx_desc,
393fb578518SFranco Fichtner 			na->num_rx_rings, na->num_rx_desc);
394fb578518SFranco Fichtner 		D("new config %s: txring %d x %d, rxring %d x %d",
395fb578518SFranco Fichtner 			NM_IFPNAME(ifp), txr, txd, rxr, rxd);
396fb578518SFranco Fichtner 	}
397fb578518SFranco Fichtner 	if (na->active_fds == 0) {
398fb578518SFranco Fichtner 		D("configuration changed (but fine)");
399fb578518SFranco Fichtner 		na->num_tx_rings = txr;
400fb578518SFranco Fichtner 		na->num_tx_desc = txd;
401fb578518SFranco Fichtner 		na->num_rx_rings = rxr;
402fb578518SFranco Fichtner 		na->num_rx_desc = rxd;
403fb578518SFranco Fichtner 		return 0;
404fb578518SFranco Fichtner 	}
405fb578518SFranco Fichtner 	D("configuration changed while active, this is bad...");
406fb578518SFranco Fichtner 	return 1;
407fb578518SFranco Fichtner }
408fb578518SFranco Fichtner 
409fb578518SFranco Fichtner 
410fb578518SFranco Fichtner int
netmap_krings_create(struct netmap_adapter * na,u_int ntx,u_int nrx,u_int tailroom)411fb578518SFranco Fichtner netmap_krings_create(struct netmap_adapter *na, u_int ntx, u_int nrx, u_int tailroom)
412fb578518SFranco Fichtner {
413fb578518SFranco Fichtner 	u_int i, len, ndesc;
414fb578518SFranco Fichtner 	struct netmap_kring *kring;
415fb578518SFranco Fichtner 
416fb578518SFranco Fichtner 	len = (ntx + nrx) * sizeof(struct netmap_kring) + tailroom;
417fb578518SFranco Fichtner 
418ed9bd855SFranco Fichtner 	na->tx_rings = kmalloc((size_t)len, M_DEVBUF, M_NOWAIT | M_ZERO);
419fb578518SFranco Fichtner 	if (na->tx_rings == NULL) {
420fb578518SFranco Fichtner 		D("Cannot allocate krings");
421fb578518SFranco Fichtner 		return ENOMEM;
422fb578518SFranco Fichtner 	}
423fb578518SFranco Fichtner 	na->rx_rings = na->tx_rings + ntx;
424fb578518SFranco Fichtner 
425fb578518SFranco Fichtner 	ndesc = na->num_tx_desc;
426fb578518SFranco Fichtner 	for (i = 0; i < ntx; i++) { /* Transmit rings */
427fb578518SFranco Fichtner 		kring = &na->tx_rings[i];
428fb578518SFranco Fichtner 		bzero(kring, sizeof(*kring));
429fb578518SFranco Fichtner 		kring->na = na;
430fb578518SFranco Fichtner 		kring->nkr_num_slots = ndesc;
431fb578518SFranco Fichtner 		/*
432fb578518SFranco Fichtner 		 * IMPORTANT:
433fb578518SFranco Fichtner 		 * Always keep one slot empty, so we can detect new
434fb578518SFranco Fichtner 		 * transmissions comparing cur and nr_hwcur (they are
435fb578518SFranco Fichtner 		 * the same only if there are no new transmissions).
436fb578518SFranco Fichtner 		 */
437fb578518SFranco Fichtner 		kring->nr_hwavail = ndesc - 1;
438bf9f7c16SFranco Fichtner 		lockinit(&kring->q_lock, "nm_txq_lock", 0, LK_CANRECURSE);
439fb578518SFranco Fichtner 		init_waitqueue_head(&kring->si);
440fb578518SFranco Fichtner 	}
441fb578518SFranco Fichtner 
442fb578518SFranco Fichtner 	ndesc = na->num_rx_desc;
443fb578518SFranco Fichtner 	for (i = 0; i < nrx; i++) { /* Receive rings */
444fb578518SFranco Fichtner 		kring = &na->rx_rings[i];
445fb578518SFranco Fichtner 		bzero(kring, sizeof(*kring));
446fb578518SFranco Fichtner 		kring->na = na;
447fb578518SFranco Fichtner 		kring->nkr_num_slots = ndesc;
448bf9f7c16SFranco Fichtner 		lockinit(&kring->q_lock, "nm_rxq_lock", 0, LK_CANRECURSE);
449fb578518SFranco Fichtner 		init_waitqueue_head(&kring->si);
450fb578518SFranco Fichtner 	}
451fb578518SFranco Fichtner 	init_waitqueue_head(&na->tx_si);
452fb578518SFranco Fichtner 	init_waitqueue_head(&na->rx_si);
453fb578518SFranco Fichtner 
454fb578518SFranco Fichtner 	na->tailroom = na->rx_rings + nrx;
455fb578518SFranco Fichtner 
456fb578518SFranco Fichtner 	return 0;
457fb578518SFranco Fichtner 
458fb578518SFranco Fichtner }
459fb578518SFranco Fichtner 
460fb578518SFranco Fichtner 
461fb578518SFranco Fichtner void
netmap_krings_delete(struct netmap_adapter * na)462fb578518SFranco Fichtner netmap_krings_delete(struct netmap_adapter *na)
463fb578518SFranco Fichtner {
464fb578518SFranco Fichtner 	int i;
465fb578518SFranco Fichtner 
466fb578518SFranco Fichtner 	for (i = 0; i < na->num_tx_rings + 1; i++) {
467ed9bd855SFranco Fichtner 		lockuninit(&na->tx_rings[i].q_lock);
468fb578518SFranco Fichtner 	}
469fb578518SFranco Fichtner 	for (i = 0; i < na->num_rx_rings + 1; i++) {
470ed9bd855SFranco Fichtner 		lockuninit(&na->rx_rings[i].q_lock);
471fb578518SFranco Fichtner 	}
472ed9bd855SFranco Fichtner 	kfree(na->tx_rings, M_DEVBUF);
473fb578518SFranco Fichtner 	na->tx_rings = na->rx_rings = na->tailroom = NULL;
474fb578518SFranco Fichtner }
475fb578518SFranco Fichtner 
476fb578518SFranco Fichtner 
477fb578518SFranco Fichtner static struct netmap_if*
netmap_if_new(const char * ifname,struct netmap_adapter * na)478fb578518SFranco Fichtner netmap_if_new(const char *ifname, struct netmap_adapter *na)
479fb578518SFranco Fichtner {
480fb578518SFranco Fichtner 	struct netmap_if *nifp;
481fb578518SFranco Fichtner 
482fb578518SFranco Fichtner 	if (netmap_update_config(na)) {
483fb578518SFranco Fichtner 		/* configuration mismatch, report and fail */
484fb578518SFranco Fichtner 		return NULL;
485fb578518SFranco Fichtner 	}
486fb578518SFranco Fichtner 
487fb578518SFranco Fichtner 	if (na->active_fds)
488fb578518SFranco Fichtner 		goto final;
489fb578518SFranco Fichtner 
490fb578518SFranco Fichtner 	if (na->nm_krings_create(na))
491fb578518SFranco Fichtner 		goto cleanup;
492fb578518SFranco Fichtner 
493fb578518SFranco Fichtner 	if (netmap_mem_rings_create(na))
494fb578518SFranco Fichtner 		goto cleanup;
495fb578518SFranco Fichtner 
496fb578518SFranco Fichtner final:
497fb578518SFranco Fichtner 
498fb578518SFranco Fichtner 	nifp = netmap_mem_if_new(ifname, na);
499fb578518SFranco Fichtner 	if (nifp == NULL)
500fb578518SFranco Fichtner 		goto cleanup;
501fb578518SFranco Fichtner 
502fb578518SFranco Fichtner 	return (nifp);
503fb578518SFranco Fichtner 
504fb578518SFranco Fichtner cleanup:
505fb578518SFranco Fichtner 
506fb578518SFranco Fichtner 	if (na->active_fds == 0) {
507fb578518SFranco Fichtner 		netmap_mem_rings_delete(na);
508fb578518SFranco Fichtner 		na->nm_krings_delete(na);
509fb578518SFranco Fichtner 	}
510fb578518SFranco Fichtner 
511fb578518SFranco Fichtner 	return NULL;
512fb578518SFranco Fichtner }
513fb578518SFranco Fichtner 
514fb578518SFranco Fichtner 
515fb578518SFranco Fichtner /* grab a reference to the memory allocator, if we don't have one already.  The
516fb578518SFranco Fichtner  * reference is taken from the netmap_adapter registered with the priv.
517fb578518SFranco Fichtner  *
518fb578518SFranco Fichtner  */
519fb578518SFranco Fichtner static int
netmap_get_memory_locked(struct netmap_priv_d * p)520fb578518SFranco Fichtner netmap_get_memory_locked(struct netmap_priv_d* p)
521fb578518SFranco Fichtner {
522fb578518SFranco Fichtner 	struct netmap_mem_d *nmd;
523fb578518SFranco Fichtner 	int error = 0;
524fb578518SFranco Fichtner 
525fb578518SFranco Fichtner 	if (p->np_na == NULL) {
526fb578518SFranco Fichtner 		if (!netmap_mmap_unreg)
527fb578518SFranco Fichtner 			return ENODEV;
528fb578518SFranco Fichtner 		/* for compatibility with older versions of the API
529fb578518SFranco Fichtner  		 * we use the global allocator when no interface has been
530fb578518SFranco Fichtner  		 * registered
531fb578518SFranco Fichtner  		 */
532fb578518SFranco Fichtner 		nmd = &nm_mem;
533fb578518SFranco Fichtner 	} else {
534fb578518SFranco Fichtner 		nmd = p->np_na->nm_mem;
535fb578518SFranco Fichtner 	}
536fb578518SFranco Fichtner 	if (p->np_mref == NULL) {
537fb578518SFranco Fichtner 		error = netmap_mem_finalize(nmd);
538fb578518SFranco Fichtner 		if (!error)
539fb578518SFranco Fichtner 			p->np_mref = nmd;
540fb578518SFranco Fichtner 	} else if (p->np_mref != nmd) {
541fb578518SFranco Fichtner 		/* a virtual port has been registered, but previous
542fb578518SFranco Fichtner  		 * syscalls already used the global allocator.
543fb578518SFranco Fichtner  		 * We cannot continue
544fb578518SFranco Fichtner  		 */
545fb578518SFranco Fichtner 		error = ENODEV;
546fb578518SFranco Fichtner 	}
547fb578518SFranco Fichtner 	return error;
548fb578518SFranco Fichtner }
549fb578518SFranco Fichtner 
550fb578518SFranco Fichtner 
551fb578518SFranco Fichtner int
netmap_get_memory(struct netmap_priv_d * p)552fb578518SFranco Fichtner netmap_get_memory(struct netmap_priv_d* p)
553fb578518SFranco Fichtner {
554fb578518SFranco Fichtner 	int error;
555fb578518SFranco Fichtner 	NMG_LOCK();
556fb578518SFranco Fichtner 	error = netmap_get_memory_locked(p);
557fb578518SFranco Fichtner 	NMG_UNLOCK();
558fb578518SFranco Fichtner 	return error;
559fb578518SFranco Fichtner }
560fb578518SFranco Fichtner 
561fb578518SFranco Fichtner 
562fb578518SFranco Fichtner static int
netmap_have_memory_locked(struct netmap_priv_d * p)563fb578518SFranco Fichtner netmap_have_memory_locked(struct netmap_priv_d* p)
564fb578518SFranco Fichtner {
565fb578518SFranco Fichtner 	return p->np_mref != NULL;
566fb578518SFranco Fichtner }
567fb578518SFranco Fichtner 
568fb578518SFranco Fichtner 
569fb578518SFranco Fichtner static void
netmap_drop_memory_locked(struct netmap_priv_d * p)570fb578518SFranco Fichtner netmap_drop_memory_locked(struct netmap_priv_d* p)
571fb578518SFranco Fichtner {
572fb578518SFranco Fichtner 	if (p->np_mref) {
573fb578518SFranco Fichtner 		netmap_mem_deref(p->np_mref);
574fb578518SFranco Fichtner 		p->np_mref = NULL;
575fb578518SFranco Fichtner 	}
576fb578518SFranco Fichtner }
577fb578518SFranco Fichtner 
578fb578518SFranco Fichtner 
579fb578518SFranco Fichtner /*
580fb578518SFranco Fichtner  * File descriptor's private data destructor.
581fb578518SFranco Fichtner  *
582fb578518SFranco Fichtner  * Call nm_register(ifp,0) to stop netmap mode on the interface and
583fb578518SFranco Fichtner  * revert to normal operation. We expect that np_na->ifp has not gone.
584fb578518SFranco Fichtner  * The second argument is the nifp to work on. In some cases it is
585fb578518SFranco Fichtner  * not attached yet to the netmap_priv_d so we need to pass it as
586fb578518SFranco Fichtner  * a separate argument.
587fb578518SFranco Fichtner  */
588fb578518SFranco Fichtner /* call with NMG_LOCK held */
589fb578518SFranco Fichtner static void
netmap_do_unregif(struct netmap_priv_d * priv,struct netmap_if * nifp)590fb578518SFranco Fichtner netmap_do_unregif(struct netmap_priv_d *priv, struct netmap_if *nifp)
591fb578518SFranco Fichtner {
592fb578518SFranco Fichtner 	struct netmap_adapter *na = priv->np_na;
593fb578518SFranco Fichtner 	struct ifnet *ifp = na->ifp;
594fb578518SFranco Fichtner 
595fb578518SFranco Fichtner 	NMG_LOCK_ASSERT();
596fb578518SFranco Fichtner 	na->active_fds--;
597fb578518SFranco Fichtner 	if (na->active_fds <= 0) {	/* last instance */
598fb578518SFranco Fichtner 
599fb578518SFranco Fichtner 		if (netmap_verbose)
600fb578518SFranco Fichtner 			D("deleting last instance for %s", NM_IFPNAME(ifp));
601fb578518SFranco Fichtner 		/*
602fb578518SFranco Fichtner 		 * (TO CHECK) This function is only called
603fb578518SFranco Fichtner 		 * when the last reference to this file descriptor goes
604fb578518SFranco Fichtner 		 * away. This means we cannot have any pending poll()
605fb578518SFranco Fichtner 		 * or interrupt routine operating on the structure.
606fb578518SFranco Fichtner 		 * XXX The file may be closed in a thread while
607fb578518SFranco Fichtner 		 * another thread is using it.
608fb578518SFranco Fichtner 		 * Linux keeps the file opened until the last reference
609fb578518SFranco Fichtner 		 * by any outstanding ioctl/poll or mmap is gone.
610fb578518SFranco Fichtner 		 * FreeBSD does not track mmap()s (but we do) and
611fb578518SFranco Fichtner 		 * wakes up any sleeping poll(). Need to check what
612fb578518SFranco Fichtner 		 * happens if the close() occurs while a concurrent
613fb578518SFranco Fichtner 		 * syscall is running.
614fb578518SFranco Fichtner 		 */
615fb578518SFranco Fichtner 		if (ifp)
616fb578518SFranco Fichtner 			na->nm_register(na, 0); /* off, clear IFCAP_NETMAP */
617fb578518SFranco Fichtner 		/* Wake up any sleeping threads. netmap_poll will
618fb578518SFranco Fichtner 		 * then return POLLERR
619fb578518SFranco Fichtner 		 * XXX The wake up now must happen during *_down(), when
620fb578518SFranco Fichtner 		 * we order all activities to stop. -gl
621fb578518SFranco Fichtner 		 */
622fb578518SFranco Fichtner 		/* XXX kqueue(9) needed; these will mirror knlist_init. */
623fb578518SFranco Fichtner 		/* knlist_destroy(&na->tx_si.si_note); */
624fb578518SFranco Fichtner 		/* knlist_destroy(&na->rx_si.si_note); */
625fb578518SFranco Fichtner 
626fb578518SFranco Fichtner 		/* delete rings and buffers */
627fb578518SFranco Fichtner 		netmap_mem_rings_delete(na);
628fb578518SFranco Fichtner 		na->nm_krings_delete(na);
629fb578518SFranco Fichtner 	}
630fb578518SFranco Fichtner 	/* delete the nifp */
631fb578518SFranco Fichtner 	netmap_mem_if_delete(na, nifp);
632fb578518SFranco Fichtner }
633fb578518SFranco Fichtner 
634fb578518SFranco Fichtner 
635fb578518SFranco Fichtner /*
636fb578518SFranco Fichtner  * returns 1 if this is the last instance and we can free priv
637fb578518SFranco Fichtner  */
638fb578518SFranco Fichtner int
netmap_dtor_locked(struct netmap_priv_d * priv)639fb578518SFranco Fichtner netmap_dtor_locked(struct netmap_priv_d *priv)
640fb578518SFranco Fichtner {
641fb578518SFranco Fichtner 	struct netmap_adapter *na = priv->np_na;
642fb578518SFranco Fichtner 
643fb578518SFranco Fichtner 	/*
644fb578518SFranco Fichtner 	 * np_refcount is the number of active mmaps on
645fb578518SFranco Fichtner 	 * this file descriptor
646fb578518SFranco Fichtner 	 */
647fb578518SFranco Fichtner 	if (--priv->np_refcount > 0) {
648fb578518SFranco Fichtner 		return 0;
649fb578518SFranco Fichtner 	}
650fb578518SFranco Fichtner 	if (!na) {
651fb578518SFranco Fichtner 	    return 1; //XXX is it correct?
652fb578518SFranco Fichtner 	}
653fb578518SFranco Fichtner 	netmap_do_unregif(priv, priv->np_nifp);
654fb578518SFranco Fichtner 	priv->np_nifp = NULL;
655fb578518SFranco Fichtner 	netmap_drop_memory_locked(priv);
656fb578518SFranco Fichtner 	if (priv->np_na) {
657fb578518SFranco Fichtner 		netmap_adapter_put(na);
658fb578518SFranco Fichtner 		priv->np_na = NULL;
659fb578518SFranco Fichtner 	}
660fb578518SFranco Fichtner 	return 1;
661fb578518SFranco Fichtner }
662fb578518SFranco Fichtner 
663fb578518SFranco Fichtner 
664fb578518SFranco Fichtner void
netmap_dtor(void * data)665fb578518SFranco Fichtner netmap_dtor(void *data)
666fb578518SFranco Fichtner {
667fb578518SFranco Fichtner 	struct netmap_priv_d *priv = data;
668fb578518SFranco Fichtner 	int last_instance;
669fb578518SFranco Fichtner 
670fb578518SFranco Fichtner 	NMG_LOCK();
671fb578518SFranco Fichtner 	last_instance = netmap_dtor_locked(priv);
672fb578518SFranco Fichtner 	NMG_UNLOCK();
673fb578518SFranco Fichtner 	if (last_instance) {
674fb578518SFranco Fichtner 		bzero(priv, sizeof(*priv));	/* for safety */
675ed9bd855SFranco Fichtner 		kfree(priv, M_DEVBUF);
676fb578518SFranco Fichtner 	}
677fb578518SFranco Fichtner }
678fb578518SFranco Fichtner 
679fb578518SFranco Fichtner 
680fb578518SFranco Fichtner 
681fb578518SFranco Fichtner 
682fb578518SFranco Fichtner /*
683fb578518SFranco Fichtner  * Handlers for synchronization of the queues from/to the host.
684fb578518SFranco Fichtner  * Netmap has two operating modes:
685fb578518SFranco Fichtner  * - in the default mode, the rings connected to the host stack are
686fb578518SFranco Fichtner  *   just another ring pair managed by userspace;
687fb578518SFranco Fichtner  * - in transparent mode (XXX to be defined) incoming packets
688fb578518SFranco Fichtner  *   (from the host or the NIC) are marked as NS_FORWARD upon
689fb578518SFranco Fichtner  *   arrival, and the user application has a chance to reset the
690fb578518SFranco Fichtner  *   flag for packets that should be dropped.
691fb578518SFranco Fichtner  *   On the RXSYNC or poll(), packets in RX rings between
692fb578518SFranco Fichtner  *   kring->nr_kcur and ring->cur with NS_FORWARD still set are moved
693fb578518SFranco Fichtner  *   to the other side.
694fb578518SFranco Fichtner  * The transfer NIC --> host is relatively easy, just encapsulate
695fb578518SFranco Fichtner  * into mbufs and we are done. The host --> NIC side is slightly
696fb578518SFranco Fichtner  * harder because there might not be room in the tx ring so it
697fb578518SFranco Fichtner  * might take a while before releasing the buffer.
698fb578518SFranco Fichtner  */
699fb578518SFranco Fichtner 
700fb578518SFranco Fichtner 
701fb578518SFranco Fichtner /*
702fb578518SFranco Fichtner  * pass a chain of buffers to the host stack as coming from 'dst'
703fb578518SFranco Fichtner  */
704fb578518SFranco Fichtner static void
netmap_send_up(struct ifnet * dst,struct mbq * q)705fb578518SFranco Fichtner netmap_send_up(struct ifnet *dst, struct mbq *q)
706fb578518SFranco Fichtner {
707fb578518SFranco Fichtner 	struct mbuf *m;
708fb578518SFranco Fichtner 
709fb578518SFranco Fichtner 	/* send packets up, outside the lock */
710fb578518SFranco Fichtner 	while ((m = mbq_dequeue(q)) != NULL) {
711fb578518SFranco Fichtner 		if (netmap_verbose & NM_VERB_HOST)
712fb578518SFranco Fichtner 			D("sending up pkt %p size %d", m, MBUF_LEN(m));
713fb578518SFranco Fichtner 		NM_SEND_UP(dst, m);
714fb578518SFranco Fichtner 	}
715fb578518SFranco Fichtner 	mbq_destroy(q);
716fb578518SFranco Fichtner }
717fb578518SFranco Fichtner 
718fb578518SFranco Fichtner 
719fb578518SFranco Fichtner /*
720fb578518SFranco Fichtner  * put a copy of the buffers marked NS_FORWARD into an mbuf chain.
721fb578518SFranco Fichtner  * Run from hwcur to cur - reserved
722fb578518SFranco Fichtner  */
723fb578518SFranco Fichtner static void
netmap_grab_packets(struct netmap_kring * kring,struct mbq * q,int force)724fb578518SFranco Fichtner netmap_grab_packets(struct netmap_kring *kring, struct mbq *q, int force)
725fb578518SFranco Fichtner {
726fb578518SFranco Fichtner 	/* Take packets from hwcur to cur-reserved and pass them up.
727fb578518SFranco Fichtner 	 * In case of no buffers we give up. At the end of the loop,
728fb578518SFranco Fichtner 	 * the queue is drained in all cases.
729fb578518SFranco Fichtner 	 * XXX handle reserved
730fb578518SFranco Fichtner 	 */
731fb578518SFranco Fichtner 	u_int lim = kring->nkr_num_slots - 1;
732fb578518SFranco Fichtner 	struct mbuf *m;
733fb578518SFranco Fichtner 	u_int k = kring->ring->cur, n = kring->ring->reserved;
734fb578518SFranco Fichtner 	struct netmap_adapter *na = kring->na;
735fb578518SFranco Fichtner 
736fb578518SFranco Fichtner 	/* compute the final position, ring->cur - ring->reserved */
737fb578518SFranco Fichtner 	if (n > 0) {
738fb578518SFranco Fichtner 		if (k < n)
739fb578518SFranco Fichtner 			k += kring->nkr_num_slots;
740fb578518SFranco Fichtner 		k += n;
741fb578518SFranco Fichtner 	}
742fb578518SFranco Fichtner 	for (n = kring->nr_hwcur; n != k;) {
743fb578518SFranco Fichtner 		struct netmap_slot *slot = &kring->ring->slot[n];
744fb578518SFranco Fichtner 
745fb578518SFranco Fichtner 		n = nm_next(n, lim);
746fb578518SFranco Fichtner 		if ((slot->flags & NS_FORWARD) == 0 && !force)
747fb578518SFranco Fichtner 			continue;
748fb578518SFranco Fichtner 		if (slot->len < 14 || slot->len > NETMAP_BDG_BUF_SIZE(na->nm_mem)) {
749fb578518SFranco Fichtner 			D("bad pkt at %d len %d", n, slot->len);
750fb578518SFranco Fichtner 			continue;
751fb578518SFranco Fichtner 		}
752fb578518SFranco Fichtner 		slot->flags &= ~NS_FORWARD; // XXX needed ?
753fb578518SFranco Fichtner 		/* XXX adapt to the case of a multisegment packet */
754afd2da4dSMatthew Dillon 		m = m_devget(BDG_NMB(na, slot), slot->len, 0, na->ifp);
755fb578518SFranco Fichtner 
756fb578518SFranco Fichtner 		if (m == NULL)
757fb578518SFranco Fichtner 			break;
758fb578518SFranco Fichtner 		mbq_enqueue(q, m);
759fb578518SFranco Fichtner 	}
760fb578518SFranco Fichtner }
761fb578518SFranco Fichtner 
762fb578518SFranco Fichtner 
763fb578518SFranco Fichtner /*
764fb578518SFranco Fichtner  * The host ring has packets from nr_hwcur to (cur - reserved)
765fb578518SFranco Fichtner  * to be sent down to the NIC.
766fb578518SFranco Fichtner  * We need to use the queue lock on the source (host RX ring)
767fb578518SFranco Fichtner  * to protect against netmap_transmit.
768fb578518SFranco Fichtner  * If the user is well behaved we do not need to acquire locks
769fb578518SFranco Fichtner  * on the destination(s),
770fb578518SFranco Fichtner  * so we only need to make sure that there are no panics because
771fb578518SFranco Fichtner  * of user errors.
772fb578518SFranco Fichtner  * XXX verify
773fb578518SFranco Fichtner  *
774fb578518SFranco Fichtner  * We scan the tx rings, which have just been
775fb578518SFranco Fichtner  * flushed so nr_hwcur == cur. Pushing packets down means
776fb578518SFranco Fichtner  * increment cur and decrement avail.
777fb578518SFranco Fichtner  * XXX to be verified
778fb578518SFranco Fichtner  */
779fb578518SFranco Fichtner static void
netmap_sw_to_nic(struct netmap_adapter * na)780fb578518SFranco Fichtner netmap_sw_to_nic(struct netmap_adapter *na)
781fb578518SFranco Fichtner {
782fb578518SFranco Fichtner 	struct netmap_kring *kring = &na->rx_rings[na->num_rx_rings];
783fb578518SFranco Fichtner 	struct netmap_kring *k1 = &na->tx_rings[0];
784fb578518SFranco Fichtner 	u_int i, howmany, src_lim, dst_lim;
785fb578518SFranco Fichtner 
786fb578518SFranco Fichtner 	/* XXX we should also check that the carrier is on */
787fb578518SFranco Fichtner 	if (kring->nkr_stopped)
788fb578518SFranco Fichtner 		return;
789fb578518SFranco Fichtner 
790ed9bd855SFranco Fichtner 	lockmgr(&kring->q_lock, LK_EXCLUSIVE);
791fb578518SFranco Fichtner 
792fb578518SFranco Fichtner 	if (kring->nkr_stopped)
793fb578518SFranco Fichtner 		goto out;
794fb578518SFranco Fichtner 
795fb578518SFranco Fichtner 	howmany = kring->nr_hwavail;	/* XXX otherwise cur - reserved - nr_hwcur */
796fb578518SFranco Fichtner 
797fb578518SFranco Fichtner 	src_lim = kring->nkr_num_slots - 1;
798fb578518SFranco Fichtner 	for (i = 0; howmany > 0 && i < na->num_tx_rings; i++, k1++) {
799fb578518SFranco Fichtner 		ND("%d packets left to ring %d (space %d)", howmany, i, k1->nr_hwavail);
800fb578518SFranco Fichtner 		dst_lim = k1->nkr_num_slots - 1;
801fb578518SFranco Fichtner 		while (howmany > 0 && k1->ring->avail > 0) {
802fb578518SFranco Fichtner 			struct netmap_slot *src, *dst, tmp;
803fb578518SFranco Fichtner 			src = &kring->ring->slot[kring->nr_hwcur];
804fb578518SFranco Fichtner 			dst = &k1->ring->slot[k1->ring->cur];
805fb578518SFranco Fichtner 			tmp = *src;
806fb578518SFranco Fichtner 			src->buf_idx = dst->buf_idx;
807fb578518SFranco Fichtner 			src->flags = NS_BUF_CHANGED;
808fb578518SFranco Fichtner 
809fb578518SFranco Fichtner 			dst->buf_idx = tmp.buf_idx;
810fb578518SFranco Fichtner 			dst->len = tmp.len;
811fb578518SFranco Fichtner 			dst->flags = NS_BUF_CHANGED;
812fb578518SFranco Fichtner 			ND("out len %d buf %d from %d to %d",
813fb578518SFranco Fichtner 				dst->len, dst->buf_idx,
814fb578518SFranco Fichtner 				kring->nr_hwcur, k1->ring->cur);
815fb578518SFranco Fichtner 
816fb578518SFranco Fichtner 			kring->nr_hwcur = nm_next(kring->nr_hwcur, src_lim);
817fb578518SFranco Fichtner 			howmany--;
818fb578518SFranco Fichtner 			kring->nr_hwavail--;
819fb578518SFranco Fichtner 			k1->ring->cur = nm_next(k1->ring->cur, dst_lim);
820fb578518SFranco Fichtner 			k1->ring->avail--;
821fb578518SFranco Fichtner 		}
822fb578518SFranco Fichtner 		kring->ring->cur = kring->nr_hwcur; // XXX
823fb578518SFranco Fichtner 		k1++; // XXX why?
824fb578518SFranco Fichtner 	}
825fb578518SFranco Fichtner out:
826ed9bd855SFranco Fichtner 	lockmgr(&kring->q_lock, LK_RELEASE);
827fb578518SFranco Fichtner }
828fb578518SFranco Fichtner 
829fb578518SFranco Fichtner 
830fb578518SFranco Fichtner /*
831fb578518SFranco Fichtner  * netmap_txsync_to_host() passes packets up. We are called from a
832fb578518SFranco Fichtner  * system call in user process context, and the only contention
833fb578518SFranco Fichtner  * can be among multiple user threads erroneously calling
834fb578518SFranco Fichtner  * this routine concurrently.
835fb578518SFranco Fichtner  */
836fb578518SFranco Fichtner void
netmap_txsync_to_host(struct netmap_adapter * na)837fb578518SFranco Fichtner netmap_txsync_to_host(struct netmap_adapter *na)
838fb578518SFranco Fichtner {
839fb578518SFranco Fichtner 	struct netmap_kring *kring = &na->tx_rings[na->num_tx_rings];
840fb578518SFranco Fichtner 	struct netmap_ring *ring = kring->ring;
841fb578518SFranco Fichtner 	u_int k, lim = kring->nkr_num_slots - 1;
842fb578518SFranco Fichtner 	struct mbq q;
843fb578518SFranco Fichtner 	int error;
844fb578518SFranco Fichtner 
845fb578518SFranco Fichtner 	error = nm_kr_tryget(kring);
846fb578518SFranco Fichtner 	if (error) {
847fb578518SFranco Fichtner 		if (error == NM_KR_BUSY)
848fb578518SFranco Fichtner 			D("ring %p busy (user error)", kring);
849fb578518SFranco Fichtner 		return;
850fb578518SFranco Fichtner 	}
851fb578518SFranco Fichtner 	k = ring->cur;
852fb578518SFranco Fichtner 	if (k > lim) {
853fb578518SFranco Fichtner 		D("invalid ring index in stack TX kring %p", kring);
854fb578518SFranco Fichtner 		netmap_ring_reinit(kring);
855fb578518SFranco Fichtner 		nm_kr_put(kring);
856fb578518SFranco Fichtner 		return;
857fb578518SFranco Fichtner 	}
858fb578518SFranco Fichtner 
859fb578518SFranco Fichtner 	/* Take packets from hwcur to cur and pass them up.
860fb578518SFranco Fichtner 	 * In case of no buffers we give up. At the end of the loop,
861fb578518SFranco Fichtner 	 * the queue is drained in all cases.
862fb578518SFranco Fichtner 	 */
863fb578518SFranco Fichtner 	mbq_init(&q);
864fb578518SFranco Fichtner 	netmap_grab_packets(kring, &q, 1);
865fb578518SFranco Fichtner 	kring->nr_hwcur = k;
866fb578518SFranco Fichtner 	kring->nr_hwavail = ring->avail = lim;
867fb578518SFranco Fichtner 
868fb578518SFranco Fichtner 	nm_kr_put(kring);
869fb578518SFranco Fichtner 	netmap_send_up(na->ifp, &q);
870fb578518SFranco Fichtner }
871fb578518SFranco Fichtner 
872fb578518SFranco Fichtner 
873fb578518SFranco Fichtner /*
874fb578518SFranco Fichtner  * rxsync backend for packets coming from the host stack.
875fb578518SFranco Fichtner  * They have been put in the queue by netmap_transmit() so we
876fb578518SFranco Fichtner  * need to protect access to the kring using a lock.
877fb578518SFranco Fichtner  *
878fb578518SFranco Fichtner  * This routine also does the selrecord if called from the poll handler
879fb578518SFranco Fichtner  * (we know because td != NULL).
880fb578518SFranco Fichtner  *
881fb578518SFranco Fichtner  * NOTE: on linux, selrecord() is defined as a macro and uses pwait
882fb578518SFranco Fichtner  *     as an additional hidden argument.
883fb578518SFranco Fichtner  */
884fb578518SFranco Fichtner static void
netmap_rxsync_from_host(struct netmap_adapter * na,struct thread * td,void * pwait)885fb578518SFranco Fichtner netmap_rxsync_from_host(struct netmap_adapter *na, struct thread *td, void *pwait)
886fb578518SFranco Fichtner {
887fb578518SFranco Fichtner 	struct netmap_kring *kring = &na->rx_rings[na->num_rx_rings];
888fb578518SFranco Fichtner 	struct netmap_ring *ring = kring->ring;
889fb578518SFranco Fichtner 	u_int j, n, lim = kring->nkr_num_slots;
890fb578518SFranco Fichtner 	u_int k = ring->cur, resvd = ring->reserved;
891fb578518SFranco Fichtner 
892fb578518SFranco Fichtner 	(void)pwait;	/* disable unused warnings */
893fb578518SFranco Fichtner 
894fb578518SFranco Fichtner 	if (kring->nkr_stopped) /* check a first time without lock */
895fb578518SFranco Fichtner 		return;
896fb578518SFranco Fichtner 
897ed9bd855SFranco Fichtner 	lockmgr(&kring->q_lock, LK_EXCLUSIVE);
898fb578518SFranco Fichtner 
899fb578518SFranco Fichtner 	if (kring->nkr_stopped)  /* check again with lock held */
900fb578518SFranco Fichtner 		goto unlock_out;
901fb578518SFranco Fichtner 
902fb578518SFranco Fichtner 	if (k >= lim) {
903fb578518SFranco Fichtner 		netmap_ring_reinit(kring);
904fb578518SFranco Fichtner 		goto unlock_out;
905fb578518SFranco Fichtner 	}
906fb578518SFranco Fichtner 	/* new packets are already set in nr_hwavail */
907fb578518SFranco Fichtner 	/* skip past packets that userspace has released */
908fb578518SFranco Fichtner 	j = kring->nr_hwcur;
909fb578518SFranco Fichtner 	if (resvd > 0) {
910fb578518SFranco Fichtner 		if (resvd + ring->avail >= lim + 1) {
911fb578518SFranco Fichtner 			D("XXX invalid reserve/avail %d %d", resvd, ring->avail);
912fb578518SFranco Fichtner 			ring->reserved = resvd = 0; // XXX panic...
913fb578518SFranco Fichtner 		}
914fb578518SFranco Fichtner 		k = (k >= resvd) ? k - resvd : k + lim - resvd;
915fb578518SFranco Fichtner 	}
916fb578518SFranco Fichtner 	if (j != k) {
917fb578518SFranco Fichtner 		n = k >= j ? k - j : k + lim - j;
918fb578518SFranco Fichtner 		kring->nr_hwavail -= n;
919fb578518SFranco Fichtner 		kring->nr_hwcur = k;
920fb578518SFranco Fichtner 	}
921fb578518SFranco Fichtner 	k = ring->avail = kring->nr_hwavail - resvd;
922fb578518SFranco Fichtner 	if (k == 0 && td)
923b3f97fadSFranco Fichtner 		KNOTE(&kring->si.ki_note, 0);
924fb578518SFranco Fichtner 	if (k && (netmap_verbose & NM_VERB_HOST))
925fb578518SFranco Fichtner 		D("%d pkts from stack", k);
926fb578518SFranco Fichtner unlock_out:
927fb578518SFranco Fichtner 
928ed9bd855SFranco Fichtner 	lockmgr(&kring->q_lock, LK_RELEASE);
929fb578518SFranco Fichtner }
930fb578518SFranco Fichtner 
931fb578518SFranco Fichtner 
932fb578518SFranco Fichtner /* Get a netmap adapter for the port.
933fb578518SFranco Fichtner  *
934fb578518SFranco Fichtner  * If it is possible to satisfy the request, return 0
935fb578518SFranco Fichtner  * with *na containing the netmap adapter found.
936fb578518SFranco Fichtner  * Otherwise return an error code, with *na containing NULL.
937fb578518SFranco Fichtner  *
938fb578518SFranco Fichtner  * When the port is attached to a bridge, we always return
939fb578518SFranco Fichtner  * EBUSY.
940fb578518SFranco Fichtner  * Otherwise, if the port is already bound to a file descriptor,
941fb578518SFranco Fichtner  * then we unconditionally return the existing adapter into *na.
942fb578518SFranco Fichtner  * In all the other cases, we return (into *na) either native,
943fb578518SFranco Fichtner  * generic or NULL, according to the following table:
944fb578518SFranco Fichtner  *
945fb578518SFranco Fichtner  *					native_support
946fb578518SFranco Fichtner  * active_fds   dev.netmap.admode         YES     NO
947fb578518SFranco Fichtner  * -------------------------------------------------------
948fb578518SFranco Fichtner  *    >0              *                 NA(ifp) NA(ifp)
949fb578518SFranco Fichtner  *
950fb578518SFranco Fichtner  *     0        NETMAP_ADMODE_BEST      NATIVE  GENERIC
951fb578518SFranco Fichtner  *     0        NETMAP_ADMODE_NATIVE    NATIVE   NULL
952fb578518SFranco Fichtner  *     0        NETMAP_ADMODE_GENERIC   GENERIC GENERIC
953fb578518SFranco Fichtner  *
954fb578518SFranco Fichtner  */
955fb578518SFranco Fichtner 
956fb578518SFranco Fichtner int
netmap_get_hw_na(struct ifnet * ifp,struct netmap_adapter ** na)957fb578518SFranco Fichtner netmap_get_hw_na(struct ifnet *ifp, struct netmap_adapter **na)
958fb578518SFranco Fichtner {
959fb578518SFranco Fichtner 	/* generic support */
960fb578518SFranco Fichtner 	int i = netmap_admode;	/* Take a snapshot. */
961fb578518SFranco Fichtner 	int error = 0;
962fb578518SFranco Fichtner 	struct netmap_adapter *prev_na;
963fb578518SFranco Fichtner 	struct netmap_generic_adapter *gna;
964fb578518SFranco Fichtner 
965fb578518SFranco Fichtner 	*na = NULL; /* default */
966fb578518SFranco Fichtner 
967fb578518SFranco Fichtner 	/* reset in case of invalid value */
968fb578518SFranco Fichtner 	if (i < NETMAP_ADMODE_BEST || i >= NETMAP_ADMODE_LAST)
969fb578518SFranco Fichtner 		i = netmap_admode = NETMAP_ADMODE_BEST;
970fb578518SFranco Fichtner 
971fb578518SFranco Fichtner 	if (NETMAP_CAPABLE(ifp)) {
972fb578518SFranco Fichtner 		/* If an adapter already exists, but is
973fb578518SFranco Fichtner 		 * attached to a vale port, we report that the
974fb578518SFranco Fichtner 		 * port is busy.
975fb578518SFranco Fichtner 		 */
976fb578518SFranco Fichtner 		if (NETMAP_OWNED_BY_KERN(NA(ifp)))
977fb578518SFranco Fichtner 			return EBUSY;
978fb578518SFranco Fichtner 
979fb578518SFranco Fichtner 		/* If an adapter already exists, return it if
980fb578518SFranco Fichtner 		 * there are active file descriptors or if
981fb578518SFranco Fichtner 		 * netmap is not forced to use generic
982fb578518SFranco Fichtner 		 * adapters.
983fb578518SFranco Fichtner 		 */
984fb578518SFranco Fichtner 		if (NA(ifp)->active_fds > 0 ||
985fb578518SFranco Fichtner 				i != NETMAP_ADMODE_GENERIC) {
986fb578518SFranco Fichtner 			*na = NA(ifp);
987fb578518SFranco Fichtner 			return 0;
988fb578518SFranco Fichtner 		}
989fb578518SFranco Fichtner 	}
990fb578518SFranco Fichtner 
991fb578518SFranco Fichtner 	/* If there isn't native support and netmap is not allowed
992fb578518SFranco Fichtner 	 * to use generic adapters, we cannot satisfy the request.
993fb578518SFranco Fichtner 	 */
994fb578518SFranco Fichtner 	if (!NETMAP_CAPABLE(ifp) && i == NETMAP_ADMODE_NATIVE)
995fb578518SFranco Fichtner 		return EINVAL;
996fb578518SFranco Fichtner 
997fb578518SFranco Fichtner 	/* Otherwise, create a generic adapter and return it,
998fb578518SFranco Fichtner 	 * saving the previously used netmap adapter, if any.
999fb578518SFranco Fichtner 	 *
1000fb578518SFranco Fichtner 	 * Note that here 'prev_na', if not NULL, MUST be a
1001fb578518SFranco Fichtner 	 * native adapter, and CANNOT be a generic one. This is
1002fb578518SFranco Fichtner 	 * true because generic adapters are created on demand, and
1003fb578518SFranco Fichtner 	 * destroyed when not used anymore. Therefore, if the adapter
1004fb578518SFranco Fichtner 	 * currently attached to an interface 'ifp' is generic, it
1005fb578518SFranco Fichtner 	 * must be that
1006fb578518SFranco Fichtner 	 * (NA(ifp)->active_fds > 0 || NETMAP_OWNED_BY_KERN(NA(ifp))).
1007fb578518SFranco Fichtner 	 * Consequently, if NA(ifp) is generic, we will enter one of
1008fb578518SFranco Fichtner 	 * the branches above. This ensures that we never override
1009fb578518SFranco Fichtner 	 * a generic adapter with another generic adapter.
1010fb578518SFranco Fichtner 	 */
1011fb578518SFranco Fichtner 	prev_na = NA(ifp);
1012fb578518SFranco Fichtner 	error = generic_netmap_attach(ifp);
1013fb578518SFranco Fichtner 	if (error)
1014fb578518SFranco Fichtner 		return error;
1015fb578518SFranco Fichtner 
1016fb578518SFranco Fichtner 	*na = NA(ifp);
1017fb578518SFranco Fichtner 	gna = (struct netmap_generic_adapter*)NA(ifp);
1018fb578518SFranco Fichtner 	gna->prev = prev_na; /* save old na */
1019fb578518SFranco Fichtner 	if (prev_na != NULL) {
1020fb578518SFranco Fichtner 		// XXX add a refcount ?
1021fb578518SFranco Fichtner 		netmap_adapter_get(prev_na);
1022fb578518SFranco Fichtner 	}
1023fb578518SFranco Fichtner 	D("Created generic NA %p (prev %p)", gna, gna->prev);
1024fb578518SFranco Fichtner 
1025fb578518SFranco Fichtner 	return 0;
1026fb578518SFranco Fichtner }
1027fb578518SFranco Fichtner 
1028fb578518SFranco Fichtner 
1029fb578518SFranco Fichtner /*
1030fb578518SFranco Fichtner  * MUST BE CALLED UNDER NMG_LOCK()
1031fb578518SFranco Fichtner  *
1032fb578518SFranco Fichtner  * get a refcounted reference to an interface.
1033fb578518SFranco Fichtner  * This is always called in the execution of an ioctl().
1034fb578518SFranco Fichtner  *
1035fb578518SFranco Fichtner  * Return ENXIO if the interface does not exist, EINVAL if netmap
1036fb578518SFranco Fichtner  * is not supported by the interface.
1037fb578518SFranco Fichtner  * If successful, hold a reference.
1038fb578518SFranco Fichtner  *
1039fb578518SFranco Fichtner  * When the NIC is attached to a bridge, reference is managed
1040fb578518SFranco Fichtner  * at na->na_bdg_refcount using ADD/DROP_BDG_REF() as well as
1041fb578518SFranco Fichtner  * virtual ports.  Hence, on the final DROP_BDG_REF(), the NIC
1042fb578518SFranco Fichtner  * is detached from the bridge, then ifp's refcount is dropped (this
1043fb578518SFranco Fichtner  * is equivalent to that ifp is destroyed in case of virtual ports.
1044fb578518SFranco Fichtner  *
1045fb578518SFranco Fichtner  * This function uses if_rele() when we want to prevent the NIC from
1046fb578518SFranco Fichtner  * being detached from the bridge in error handling.  But once refcount
1047fb578518SFranco Fichtner  * is acquired by this function, it must be released using nm_if_rele().
1048fb578518SFranco Fichtner  */
1049fb578518SFranco Fichtner int
netmap_get_na(struct nmreq * nmr,struct netmap_adapter ** na,int create)1050fb578518SFranco Fichtner netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na, int create)
1051fb578518SFranco Fichtner {
1052fb578518SFranco Fichtner 	struct ifnet *ifp;
1053fb578518SFranco Fichtner 	int error = 0;
1054fb578518SFranco Fichtner 	struct netmap_adapter *ret;
1055fb578518SFranco Fichtner 
1056fb578518SFranco Fichtner 	*na = NULL;     /* default return value */
1057fb578518SFranco Fichtner 
1058fb578518SFranco Fichtner 	/* first try to see if this is a bridge port. */
1059fb578518SFranco Fichtner 	NMG_LOCK_ASSERT();
1060fb578518SFranco Fichtner 
1061fb578518SFranco Fichtner 	error = netmap_get_bdg_na(nmr, na, create);
1062fb578518SFranco Fichtner 	if (error || *na != NULL) /* valid match in netmap_get_bdg_na() */
1063fb578518SFranco Fichtner 		return error;
1064fb578518SFranco Fichtner 
1065b4051e25SSepherosa Ziehau 	ifnet_lock();
1066b4051e25SSepherosa Ziehau 
1067bf9f7c16SFranco Fichtner 	ifp = ifunit(nmr->nr_name);
1068fb578518SFranco Fichtner 	if (ifp == NULL) {
1069b4051e25SSepherosa Ziehau 		error = ENXIO;
1070b4051e25SSepherosa Ziehau 		goto out;
1071fb578518SFranco Fichtner 	}
1072fb578518SFranco Fichtner 
1073fb578518SFranco Fichtner 	error = netmap_get_hw_na(ifp, &ret);
1074fb578518SFranco Fichtner 	if (error)
1075fb578518SFranco Fichtner 		goto out;
1076fb578518SFranco Fichtner 
1077fb578518SFranco Fichtner 	if (ret != NULL) {
1078fb578518SFranco Fichtner 		/* Users cannot use the NIC attached to a bridge directly */
1079fb578518SFranco Fichtner 		if (NETMAP_OWNED_BY_KERN(ret)) {
1080fb578518SFranco Fichtner 			error = EINVAL;
1081fb578518SFranco Fichtner 			goto out;
1082fb578518SFranco Fichtner 		}
1083fb578518SFranco Fichtner 		error = 0;
1084fb578518SFranco Fichtner 		*na = ret;
1085fb578518SFranco Fichtner 		netmap_adapter_get(ret);
1086fb578518SFranco Fichtner 	}
1087fb578518SFranco Fichtner out:
1088b4051e25SSepherosa Ziehau 	ifnet_unlock();
1089fb578518SFranco Fichtner 	return error;
1090fb578518SFranco Fichtner }
1091fb578518SFranco Fichtner 
1092fb578518SFranco Fichtner 
1093fb578518SFranco Fichtner /*
1094fb578518SFranco Fichtner  * Error routine called when txsync/rxsync detects an error.
1095fb578518SFranco Fichtner  * Can't do much more than resetting cur = hwcur, avail = hwavail.
1096fb578518SFranco Fichtner  * Return 1 on reinit.
1097fb578518SFranco Fichtner  *
1098fb578518SFranco Fichtner  * This routine is only called by the upper half of the kernel.
1099fb578518SFranco Fichtner  * It only reads hwcur (which is changed only by the upper half, too)
1100fb578518SFranco Fichtner  * and hwavail (which may be changed by the lower half, but only on
1101fb578518SFranco Fichtner  * a tx ring and only to increase it, so any error will be recovered
1102fb578518SFranco Fichtner  * on the next call). For the above, we don't strictly need to call
1103fb578518SFranco Fichtner  * it under lock.
1104fb578518SFranco Fichtner  */
1105fb578518SFranco Fichtner int
netmap_ring_reinit(struct netmap_kring * kring)1106fb578518SFranco Fichtner netmap_ring_reinit(struct netmap_kring *kring)
1107fb578518SFranco Fichtner {
1108fb578518SFranco Fichtner 	struct netmap_ring *ring = kring->ring;
1109fb578518SFranco Fichtner 	u_int i, lim = kring->nkr_num_slots - 1;
1110fb578518SFranco Fichtner 	int errors = 0;
1111fb578518SFranco Fichtner 
1112fb578518SFranco Fichtner 	// XXX KASSERT nm_kr_tryget
1113fb578518SFranco Fichtner 	RD(10, "called for %s", NM_IFPNAME(kring->na->ifp));
1114fb578518SFranco Fichtner 	if (ring->cur > lim)
1115fb578518SFranco Fichtner 		errors++;
1116fb578518SFranco Fichtner 	for (i = 0; i <= lim; i++) {
1117fb578518SFranco Fichtner 		u_int idx = ring->slot[i].buf_idx;
1118fb578518SFranco Fichtner 		u_int len = ring->slot[i].len;
1119fb578518SFranco Fichtner 		if (idx < 2 || idx >= netmap_total_buffers) {
1120fb578518SFranco Fichtner 			if (!errors++)
1121fb578518SFranco Fichtner 				D("bad buffer at slot %d idx %d len %d ", i, idx, len);
1122fb578518SFranco Fichtner 			ring->slot[i].buf_idx = 0;
1123fb578518SFranco Fichtner 			ring->slot[i].len = 0;
1124fb578518SFranco Fichtner 		} else if (len > NETMAP_BDG_BUF_SIZE(kring->na->nm_mem)) {
1125fb578518SFranco Fichtner 			ring->slot[i].len = 0;
1126fb578518SFranco Fichtner 			if (!errors++)
1127fb578518SFranco Fichtner 				D("bad len %d at slot %d idx %d",
1128fb578518SFranco Fichtner 					len, i, idx);
1129fb578518SFranco Fichtner 		}
1130fb578518SFranco Fichtner 	}
1131fb578518SFranco Fichtner 	if (errors) {
1132fb578518SFranco Fichtner 		int pos = kring - kring->na->tx_rings;
1133fb578518SFranco Fichtner 		int n = kring->na->num_tx_rings + 1;
1134fb578518SFranco Fichtner 
1135fb578518SFranco Fichtner 		RD(10, "total %d errors", errors);
1136fb578518SFranco Fichtner 		errors++;
1137fb578518SFranco Fichtner 		RD(10, "%s %s[%d] reinit, cur %d -> %d avail %d -> %d",
1138fb578518SFranco Fichtner 			NM_IFPNAME(kring->na->ifp),
1139fb578518SFranco Fichtner 			pos < n ?  "TX" : "RX", pos < n ? pos : pos - n,
1140fb578518SFranco Fichtner 			ring->cur, kring->nr_hwcur,
1141fb578518SFranco Fichtner 			ring->avail, kring->nr_hwavail);
1142fb578518SFranco Fichtner 		ring->cur = kring->nr_hwcur;
1143fb578518SFranco Fichtner 		ring->avail = kring->nr_hwavail;
1144fb578518SFranco Fichtner 	}
1145fb578518SFranco Fichtner 	return (errors ? 1 : 0);
1146fb578518SFranco Fichtner }
1147fb578518SFranco Fichtner 
1148fb578518SFranco Fichtner 
1149fb578518SFranco Fichtner /*
1150fb578518SFranco Fichtner  * Set the ring ID. For devices with a single queue, a request
1151fb578518SFranco Fichtner  * for all rings is the same as a single ring.
1152fb578518SFranco Fichtner  */
1153fb578518SFranco Fichtner static int
netmap_set_ringid(struct netmap_priv_d * priv,u_int ringid)1154fb578518SFranco Fichtner netmap_set_ringid(struct netmap_priv_d *priv, u_int ringid)
1155fb578518SFranco Fichtner {
1156fb578518SFranco Fichtner 	struct netmap_adapter *na = priv->np_na;
1157fb578518SFranco Fichtner 	struct ifnet *ifp = na->ifp;
1158fb578518SFranco Fichtner 	u_int i = ringid & NETMAP_RING_MASK;
1159fb578518SFranco Fichtner 	/* initially (np_qfirst == np_qlast) we don't want to lock */
1160fb578518SFranco Fichtner 	u_int lim = na->num_rx_rings;
1161fb578518SFranco Fichtner 
1162fb578518SFranco Fichtner 	if (na->num_tx_rings > lim)
1163fb578518SFranco Fichtner 		lim = na->num_tx_rings;
1164fb578518SFranco Fichtner 	if ( (ringid & NETMAP_HW_RING) && i >= lim) {
1165fb578518SFranco Fichtner 		D("invalid ring id %d", i);
1166fb578518SFranco Fichtner 		return (EINVAL);
1167fb578518SFranco Fichtner 	}
1168fb578518SFranco Fichtner 	priv->np_ringid = ringid;
1169fb578518SFranco Fichtner 	if (ringid & NETMAP_SW_RING) {
1170fb578518SFranco Fichtner 		priv->np_qfirst = NETMAP_SW_RING;
1171fb578518SFranco Fichtner 		priv->np_qlast = 0;
1172fb578518SFranco Fichtner 	} else if (ringid & NETMAP_HW_RING) {
1173fb578518SFranco Fichtner 		priv->np_qfirst = i;
1174fb578518SFranco Fichtner 		priv->np_qlast = i + 1;
1175fb578518SFranco Fichtner 	} else {
1176fb578518SFranco Fichtner 		priv->np_qfirst = 0;
1177fb578518SFranco Fichtner 		priv->np_qlast = NETMAP_HW_RING ;
1178fb578518SFranco Fichtner 	}
1179fb578518SFranco Fichtner 	priv->np_txpoll = (ringid & NETMAP_NO_TX_POLL) ? 0 : 1;
1180fb578518SFranco Fichtner     if (netmap_verbose) {
1181fb578518SFranco Fichtner 	if (ringid & NETMAP_SW_RING)
1182fb578518SFranco Fichtner 		D("ringid %s set to SW RING", NM_IFPNAME(ifp));
1183fb578518SFranco Fichtner 	else if (ringid & NETMAP_HW_RING)
1184fb578518SFranco Fichtner 		D("ringid %s set to HW RING %d", NM_IFPNAME(ifp),
1185fb578518SFranco Fichtner 			priv->np_qfirst);
1186fb578518SFranco Fichtner 	else
1187fb578518SFranco Fichtner 		D("ringid %s set to all %d HW RINGS", NM_IFPNAME(ifp), lim);
1188fb578518SFranco Fichtner     }
1189fb578518SFranco Fichtner 	return 0;
1190fb578518SFranco Fichtner }
1191fb578518SFranco Fichtner 
1192fb578518SFranco Fichtner 
1193fb578518SFranco Fichtner /*
1194fb578518SFranco Fichtner  * possibly move the interface to netmap-mode.
1195fb578518SFranco Fichtner  * If success it returns a pointer to netmap_if, otherwise NULL.
1196fb578518SFranco Fichtner  * This must be called with NMG_LOCK held.
1197fb578518SFranco Fichtner  */
1198fb578518SFranco Fichtner struct netmap_if *
netmap_do_regif(struct netmap_priv_d * priv,struct netmap_adapter * na,uint16_t ringid,int * err)1199fb578518SFranco Fichtner netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
1200fb578518SFranco Fichtner 	uint16_t ringid, int *err)
1201fb578518SFranco Fichtner {
1202fb578518SFranco Fichtner 	struct ifnet *ifp = na->ifp;
1203fb578518SFranco Fichtner 	struct netmap_if *nifp = NULL;
1204fb578518SFranco Fichtner 	int error, need_mem = 0;
1205fb578518SFranco Fichtner 
1206fb578518SFranco Fichtner 	NMG_LOCK_ASSERT();
1207fb578518SFranco Fichtner 	/* ring configuration may have changed, fetch from the card */
1208fb578518SFranco Fichtner 	netmap_update_config(na);
1209fb578518SFranco Fichtner 	priv->np_na = na;     /* store the reference */
1210fb578518SFranco Fichtner 	error = netmap_set_ringid(priv, ringid);
1211fb578518SFranco Fichtner 	if (error)
1212fb578518SFranco Fichtner 		goto out;
1213fb578518SFranco Fichtner 	/* ensure allocators are ready */
1214fb578518SFranco Fichtner 	need_mem = !netmap_have_memory_locked(priv);
1215fb578518SFranco Fichtner 	if (need_mem) {
1216fb578518SFranco Fichtner 		error = netmap_get_memory_locked(priv);
1217fb578518SFranco Fichtner 		ND("get_memory returned %d", error);
1218fb578518SFranco Fichtner 		if (error)
1219fb578518SFranco Fichtner 			goto out;
1220fb578518SFranco Fichtner 	}
1221fb578518SFranco Fichtner 	nifp = netmap_if_new(NM_IFPNAME(ifp), na);
1222fb578518SFranco Fichtner 	if (nifp == NULL) { /* allocation failed */
1223fb578518SFranco Fichtner 		/* we should drop the allocator, but only
1224fb578518SFranco Fichtner 		 * if we were the ones who grabbed it
1225fb578518SFranco Fichtner 		 */
1226fb578518SFranco Fichtner 		error = ENOMEM;
1227fb578518SFranco Fichtner 		goto out;
1228fb578518SFranco Fichtner 	}
1229fb578518SFranco Fichtner 	na->active_fds++;
1230fb578518SFranco Fichtner 	if (ifp->if_capenable & IFCAP_NETMAP) {
1231fb578518SFranco Fichtner 		/* was already set */
1232fb578518SFranco Fichtner 	} else {
1233fb578518SFranco Fichtner 		/* Otherwise set the card in netmap mode
1234fb578518SFranco Fichtner 		 * and make it use the shared buffers.
1235fb578518SFranco Fichtner 		 *
1236fb578518SFranco Fichtner 		 * do not core lock because the race is harmless here,
1237fb578518SFranco Fichtner 		 * there cannot be any traffic to netmap_transmit()
1238fb578518SFranco Fichtner 		 */
1239fb578518SFranco Fichtner 		na->na_lut = na->nm_mem->pools[NETMAP_BUF_POOL].lut;
1240fb578518SFranco Fichtner 		ND("%p->na_lut == %p", na, na->na_lut);
1241fb578518SFranco Fichtner 		na->na_lut_objtotal = na->nm_mem->pools[NETMAP_BUF_POOL].objtotal;
1242fb578518SFranco Fichtner 		error = na->nm_register(na, 1); /* mode on */
1243fb578518SFranco Fichtner 		if (error) {
1244fb578518SFranco Fichtner 			netmap_do_unregif(priv, nifp);
1245fb578518SFranco Fichtner 			nifp = NULL;
1246fb578518SFranco Fichtner 		}
1247fb578518SFranco Fichtner 	}
1248fb578518SFranco Fichtner out:
1249fb578518SFranco Fichtner 	*err = error;
1250fb578518SFranco Fichtner 	if (error) {
1251fb578518SFranco Fichtner 		priv->np_na = NULL;
1252fb578518SFranco Fichtner 		if (need_mem)
1253fb578518SFranco Fichtner 			netmap_drop_memory_locked(priv);
1254fb578518SFranco Fichtner 	}
1255fb578518SFranco Fichtner 	if (nifp != NULL) {
1256fb578518SFranco Fichtner 		/*
1257fb578518SFranco Fichtner 		 * advertise that the interface is ready bt setting ni_nifp.
1258fb578518SFranco Fichtner 		 * The barrier is needed because readers (poll and *SYNC)
1259fb578518SFranco Fichtner 		 * check for priv->np_nifp != NULL without locking
1260fb578518SFranco Fichtner 		 */
1261fb578518SFranco Fichtner 		wmb(); /* make sure previous writes are visible to all CPUs */
1262fb578518SFranco Fichtner 		priv->np_nifp = nifp;
1263fb578518SFranco Fichtner 	}
1264fb578518SFranco Fichtner 	return nifp;
1265fb578518SFranco Fichtner }
1266fb578518SFranco Fichtner 
1267fb578518SFranco Fichtner 
1268fb578518SFranco Fichtner 
1269fb578518SFranco Fichtner /*
1270fb578518SFranco Fichtner  * ioctl(2) support for the "netmap" device.
1271fb578518SFranco Fichtner  *
1272fb578518SFranco Fichtner  * Following a list of accepted commands:
1273fb578518SFranco Fichtner  * - NIOCGINFO
1274fb578518SFranco Fichtner  * - SIOCGIFADDR	just for convenience
1275fb578518SFranco Fichtner  * - NIOCREGIF
1276fb578518SFranco Fichtner  * - NIOCUNREGIF
1277fb578518SFranco Fichtner  * - NIOCTXSYNC
1278fb578518SFranco Fichtner  * - NIOCRXSYNC
1279fb578518SFranco Fichtner  *
1280fb578518SFranco Fichtner  * Return 0 on success, errno otherwise.
1281fb578518SFranco Fichtner  */
1282fb578518SFranco Fichtner int
netmap_ioctl(struct dev_ioctl_args * ap)128313431b3eSFranco Fichtner netmap_ioctl(struct dev_ioctl_args *ap)
1284fb578518SFranco Fichtner {
1285fb578518SFranco Fichtner 	struct netmap_priv_d *priv = NULL;
1286fb578518SFranco Fichtner 	struct ifnet *ifp = NULL;
128713431b3eSFranco Fichtner 	struct nmreq *nmr = (struct nmreq *) ap->a_data;
1288fb578518SFranco Fichtner 	struct netmap_adapter *na = NULL;
1289fb578518SFranco Fichtner 	int error;
1290fb578518SFranco Fichtner 	u_int i, lim;
1291fb578518SFranco Fichtner 	struct netmap_if *nifp;
1292fb578518SFranco Fichtner 	struct netmap_kring *krings;
129313431b3eSFranco Fichtner 	u_long cmd = ap->a_cmd;
1294fb578518SFranco Fichtner 
12958b6c789bSFranco Fichtner 	error = devfs_get_cdevpriv(ap->a_fp, (void **)&priv);
12968b6c789bSFranco Fichtner 	if (error) {
12978b6c789bSFranco Fichtner 		/* XXX ENOENT should be impossible, since the priv
12988b6c789bSFranco Fichtner 		 * is now created in the open */
12998b6c789bSFranco Fichtner 		return (error == ENOENT ? ENXIO : error);
13008b6c789bSFranco Fichtner 	}
1301fb578518SFranco Fichtner 
1302fb578518SFranco Fichtner 	nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';	/* truncate name */
1303fb578518SFranco Fichtner 	switch (cmd) {
1304fb578518SFranco Fichtner 	case NIOCGINFO:		/* return capabilities etc */
1305fb578518SFranco Fichtner 		if (nmr->nr_version != NETMAP_API) {
1306fb578518SFranco Fichtner 			D("API mismatch got %d have %d",
1307fb578518SFranco Fichtner 				nmr->nr_version, NETMAP_API);
1308fb578518SFranco Fichtner 			nmr->nr_version = NETMAP_API;
1309fb578518SFranco Fichtner 			error = EINVAL;
1310fb578518SFranco Fichtner 			break;
1311fb578518SFranco Fichtner 		}
1312fb578518SFranco Fichtner 		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
1313fb578518SFranco Fichtner 			error = netmap_bdg_ctl(nmr, NULL);
1314fb578518SFranco Fichtner 			break;
1315fb578518SFranco Fichtner 		}
1316fb578518SFranco Fichtner 
1317fb578518SFranco Fichtner 		NMG_LOCK();
1318fb578518SFranco Fichtner 		do {
1319fb578518SFranco Fichtner 			/* memsize is always valid */
1320fb578518SFranco Fichtner 			struct netmap_mem_d *nmd = &nm_mem;
1321fb578518SFranco Fichtner 			u_int memflags;
1322fb578518SFranco Fichtner 
1323fb578518SFranco Fichtner 			if (nmr->nr_name[0] != '\0') {
1324fb578518SFranco Fichtner 				/* get a refcount */
1325fb578518SFranco Fichtner 				error = netmap_get_na(nmr, &na, 1 /* create */);
1326fb578518SFranco Fichtner 				if (error)
1327fb578518SFranco Fichtner 					break;
1328fb578518SFranco Fichtner 				nmd = na->nm_mem; /* get memory allocator */
1329fb578518SFranco Fichtner 			}
1330fb578518SFranco Fichtner 
1331fb578518SFranco Fichtner 			error = netmap_mem_get_info(nmd, &nmr->nr_memsize, &memflags);
1332fb578518SFranco Fichtner 			if (error)
1333fb578518SFranco Fichtner 				break;
1334fb578518SFranco Fichtner 			if (na == NULL) /* only memory info */
1335fb578518SFranco Fichtner 				break;
1336fb578518SFranco Fichtner 			nmr->nr_offset = 0;
1337fb578518SFranco Fichtner 			nmr->nr_rx_slots = nmr->nr_tx_slots = 0;
1338fb578518SFranco Fichtner 			netmap_update_config(na);
1339fb578518SFranco Fichtner 			nmr->nr_rx_rings = na->num_rx_rings;
1340fb578518SFranco Fichtner 			nmr->nr_tx_rings = na->num_tx_rings;
1341fb578518SFranco Fichtner 			nmr->nr_rx_slots = na->num_rx_desc;
1342fb578518SFranco Fichtner 			nmr->nr_tx_slots = na->num_tx_desc;
1343fb578518SFranco Fichtner 			if (memflags & NETMAP_MEM_PRIVATE)
1344fb578518SFranco Fichtner 				nmr->nr_ringid |= NETMAP_PRIV_MEM;
1345fb578518SFranco Fichtner 			netmap_adapter_put(na);
1346fb578518SFranco Fichtner 		} while (0);
1347fb578518SFranco Fichtner 		NMG_UNLOCK();
1348fb578518SFranco Fichtner 		break;
1349fb578518SFranco Fichtner 
1350fb578518SFranco Fichtner 	case NIOCREGIF:
1351fb578518SFranco Fichtner 		if (nmr->nr_version != NETMAP_API) {
1352fb578518SFranco Fichtner 			nmr->nr_version = NETMAP_API;
1353fb578518SFranco Fichtner 			error = EINVAL;
1354fb578518SFranco Fichtner 			break;
1355fb578518SFranco Fichtner 		}
1356fb578518SFranco Fichtner 		/* possibly attach/detach NIC and VALE switch */
1357fb578518SFranco Fichtner 		i = nmr->nr_cmd;
1358fb578518SFranco Fichtner 		if (i == NETMAP_BDG_ATTACH || i == NETMAP_BDG_DETACH) {
1359fb578518SFranco Fichtner 			error = netmap_bdg_ctl(nmr, NULL);
1360fb578518SFranco Fichtner 			break;
1361fb578518SFranco Fichtner 		} else if (i != 0) {
1362fb578518SFranco Fichtner 			D("nr_cmd must be 0 not %d", i);
1363fb578518SFranco Fichtner 			error = EINVAL;
1364fb578518SFranco Fichtner 			break;
1365fb578518SFranco Fichtner 		}
1366fb578518SFranco Fichtner 
1367fb578518SFranco Fichtner 		/* protect access to priv from concurrent NIOCREGIF */
1368fb578518SFranco Fichtner 		NMG_LOCK();
1369fb578518SFranco Fichtner 		do {
1370fb578518SFranco Fichtner 			u_int memflags;
1371fb578518SFranco Fichtner 
1372fb578518SFranco Fichtner 			if (priv->np_na != NULL) {	/* thread already registered */
1373fb578518SFranco Fichtner 				error = netmap_set_ringid(priv, nmr->nr_ringid);
1374fb578518SFranco Fichtner 				break;
1375fb578518SFranco Fichtner 			}
1376fb578518SFranco Fichtner 			/* find the interface and a reference */
1377fb578518SFranco Fichtner 			error = netmap_get_na(nmr, &na, 1 /* create */); /* keep reference */
1378fb578518SFranco Fichtner 			if (error)
1379fb578518SFranco Fichtner 				break;
1380fb578518SFranco Fichtner 			ifp = na->ifp;
1381fb578518SFranco Fichtner 			if (NETMAP_OWNED_BY_KERN(na)) {
1382fb578518SFranco Fichtner 				netmap_adapter_put(na);
1383fb578518SFranco Fichtner 				error = EBUSY;
1384fb578518SFranco Fichtner 				break;
1385fb578518SFranco Fichtner 			}
1386fb578518SFranco Fichtner 			nifp = netmap_do_regif(priv, na, nmr->nr_ringid, &error);
1387fb578518SFranco Fichtner 			if (!nifp) {    /* reg. failed, release priv and ref */
1388fb578518SFranco Fichtner 				netmap_adapter_put(na);
1389fb578518SFranco Fichtner 				priv->np_nifp = NULL;
1390fb578518SFranco Fichtner 				break;
1391fb578518SFranco Fichtner 			}
1392fb578518SFranco Fichtner 
1393fb578518SFranco Fichtner 			/* return the offset of the netmap_if object */
1394fb578518SFranco Fichtner 			nmr->nr_rx_rings = na->num_rx_rings;
1395fb578518SFranco Fichtner 			nmr->nr_tx_rings = na->num_tx_rings;
1396fb578518SFranco Fichtner 			nmr->nr_rx_slots = na->num_rx_desc;
1397fb578518SFranco Fichtner 			nmr->nr_tx_slots = na->num_tx_desc;
1398fb578518SFranco Fichtner 			error = netmap_mem_get_info(na->nm_mem, &nmr->nr_memsize, &memflags);
1399fb578518SFranco Fichtner 			if (error) {
1400fb578518SFranco Fichtner 				netmap_adapter_put(na);
1401fb578518SFranco Fichtner 				break;
1402fb578518SFranco Fichtner 			}
1403fb578518SFranco Fichtner 			if (memflags & NETMAP_MEM_PRIVATE) {
1404fb578518SFranco Fichtner 				nmr->nr_ringid |= NETMAP_PRIV_MEM;
1405fb578518SFranco Fichtner 				*(uint32_t *)(uintptr_t)&nifp->ni_flags |= NI_PRIV_MEM;
1406fb578518SFranco Fichtner 			}
1407fb578518SFranco Fichtner 			nmr->nr_offset = netmap_mem_if_offset(na->nm_mem, nifp);
1408fb578518SFranco Fichtner 		} while (0);
1409fb578518SFranco Fichtner 		NMG_UNLOCK();
1410fb578518SFranco Fichtner 		break;
1411fb578518SFranco Fichtner 
1412fb578518SFranco Fichtner 	case NIOCUNREGIF:
1413fb578518SFranco Fichtner 		// XXX we have no data here ?
1414fb578518SFranco Fichtner 		D("deprecated, data is %p", nmr);
1415fb578518SFranco Fichtner 		error = EINVAL;
1416fb578518SFranco Fichtner 		break;
1417fb578518SFranco Fichtner 
1418fb578518SFranco Fichtner 	case NIOCTXSYNC:
1419fb578518SFranco Fichtner 	case NIOCRXSYNC:
1420fb578518SFranco Fichtner 		nifp = priv->np_nifp;
1421fb578518SFranco Fichtner 
1422fb578518SFranco Fichtner 		if (nifp == NULL) {
1423fb578518SFranco Fichtner 			error = ENXIO;
1424fb578518SFranco Fichtner 			break;
1425fb578518SFranco Fichtner 		}
1426fb578518SFranco Fichtner 		rmb(); /* make sure following reads are not from cache */
1427fb578518SFranco Fichtner 
1428fb578518SFranco Fichtner 		na = priv->np_na;      /* we have a reference */
1429fb578518SFranco Fichtner 
1430fb578518SFranco Fichtner 		if (na == NULL) {
1431fb578518SFranco Fichtner 			D("Internal error: nifp != NULL && na == NULL");
1432fb578518SFranco Fichtner 			error = ENXIO;
1433fb578518SFranco Fichtner 			break;
1434fb578518SFranco Fichtner 		}
1435fb578518SFranco Fichtner 
1436fb578518SFranco Fichtner 		ifp = na->ifp;
1437fb578518SFranco Fichtner 		if (ifp == NULL) {
1438fb578518SFranco Fichtner 			RD(1, "the ifp is gone");
1439fb578518SFranco Fichtner 			error = ENXIO;
1440fb578518SFranco Fichtner 			break;
1441fb578518SFranco Fichtner 		}
1442fb578518SFranco Fichtner 
1443fb578518SFranco Fichtner 		if (priv->np_qfirst == NETMAP_SW_RING) { /* host rings */
1444fb578518SFranco Fichtner 			if (cmd == NIOCTXSYNC)
1445fb578518SFranco Fichtner 				netmap_txsync_to_host(na);
1446fb578518SFranco Fichtner 			else
1447fb578518SFranco Fichtner 				netmap_rxsync_from_host(na, NULL, NULL);
1448fb578518SFranco Fichtner 			break;
1449fb578518SFranco Fichtner 		}
1450fb578518SFranco Fichtner 		/* find the last ring to scan */
1451fb578518SFranco Fichtner 		lim = priv->np_qlast;
1452fb578518SFranco Fichtner 		if (lim == NETMAP_HW_RING)
1453fb578518SFranco Fichtner 			lim = (cmd == NIOCTXSYNC) ?
1454fb578518SFranco Fichtner 			    na->num_tx_rings : na->num_rx_rings;
1455fb578518SFranco Fichtner 
1456fb578518SFranco Fichtner 		krings = (cmd == NIOCTXSYNC) ? na->tx_rings : na->rx_rings;
1457fb578518SFranco Fichtner 		for (i = priv->np_qfirst; i < lim; i++) {
1458fb578518SFranco Fichtner 			struct netmap_kring *kring = krings + i;
1459fb578518SFranco Fichtner 			if (nm_kr_tryget(kring)) {
1460fb578518SFranco Fichtner 				error = EBUSY;
1461fb578518SFranco Fichtner 				goto out;
1462fb578518SFranco Fichtner 			}
1463fb578518SFranco Fichtner 			if (cmd == NIOCTXSYNC) {
1464fb578518SFranco Fichtner 				if (netmap_verbose & NM_VERB_TXSYNC)
1465fb578518SFranco Fichtner 					D("pre txsync ring %d cur %d hwcur %d",
1466fb578518SFranco Fichtner 					    i, kring->ring->cur,
1467fb578518SFranco Fichtner 					    kring->nr_hwcur);
1468fb578518SFranco Fichtner 				na->nm_txsync(na, i, NAF_FORCE_RECLAIM);
1469fb578518SFranco Fichtner 				if (netmap_verbose & NM_VERB_TXSYNC)
1470fb578518SFranco Fichtner 					D("post txsync ring %d cur %d hwcur %d",
1471fb578518SFranco Fichtner 					    i, kring->ring->cur,
1472fb578518SFranco Fichtner 					    kring->nr_hwcur);
1473fb578518SFranco Fichtner 			} else {
1474fb578518SFranco Fichtner 				na->nm_rxsync(na, i, NAF_FORCE_READ);
1475fb578518SFranco Fichtner 				microtime(&na->rx_rings[i].ring->ts);
1476fb578518SFranco Fichtner 			}
1477fb578518SFranco Fichtner 			nm_kr_put(kring);
1478fb578518SFranco Fichtner 		}
1479fb578518SFranco Fichtner 
1480fb578518SFranco Fichtner 		break;
1481fb578518SFranco Fichtner 	case BIOCIMMEDIATE:
1482fb578518SFranco Fichtner 	case BIOCGHDRCMPLT:
1483fb578518SFranco Fichtner 	case BIOCSHDRCMPLT:
1484fb578518SFranco Fichtner 	case BIOCSSEESENT:
1485fb578518SFranco Fichtner 		D("ignore BIOCIMMEDIATE/BIOCSHDRCMPLT/BIOCSHDRCMPLT/BIOCSSEESENT");
1486fb578518SFranco Fichtner 		break;
1487fb578518SFranco Fichtner 
1488fb578518SFranco Fichtner 	default:	/* allow device-specific ioctls */
1489fb578518SFranco Fichtner 	    {
1490fb578518SFranco Fichtner 		struct socket so;
1491fb578518SFranco Fichtner 
1492fb578518SFranco Fichtner 		bzero(&so, sizeof(so));
1493fb578518SFranco Fichtner 		NMG_LOCK();
1494fb578518SFranco Fichtner 		error = netmap_get_na(nmr, &na, 0 /* don't create */); /* keep reference */
1495fb578518SFranco Fichtner 		if (error) {
1496fb578518SFranco Fichtner 			netmap_adapter_put(na);
1497fb578518SFranco Fichtner 			NMG_UNLOCK();
1498fb578518SFranco Fichtner 			break;
1499fb578518SFranco Fichtner 		}
1500fb578518SFranco Fichtner 		ifp = na->ifp;
1501fb578518SFranco Fichtner 		// so->so_proto not null.
150213431b3eSFranco Fichtner 		error = ifioctl(&so, cmd, ap->a_data, ap->a_cred);
1503fb578518SFranco Fichtner 		netmap_adapter_put(na);
1504fb578518SFranco Fichtner 		NMG_UNLOCK();
1505fb578518SFranco Fichtner 		break;
1506fb578518SFranco Fichtner 	    }
1507fb578518SFranco Fichtner 	}
1508fb578518SFranco Fichtner out:
1509fb578518SFranco Fichtner 
1510fb578518SFranco Fichtner 	return (error);
1511fb578518SFranco Fichtner }
1512fb578518SFranco Fichtner 
1513f27ed164SFranco Fichtner static int
netmap_kqfilter_event(struct knote * kn,long hint)1514f27ed164SFranco Fichtner netmap_kqfilter_event(struct knote *kn, long hint)
1515f27ed164SFranco Fichtner {
1516f27ed164SFranco Fichtner 	return (0);
1517f27ed164SFranco Fichtner }
1518f27ed164SFranco Fichtner 
1519f27ed164SFranco Fichtner static void
netmap_kqfilter_detach(struct knote * kn)1520f27ed164SFranco Fichtner netmap_kqfilter_detach(struct knote *kn)
1521f27ed164SFranco Fichtner {
1522f27ed164SFranco Fichtner }
1523f27ed164SFranco Fichtner 
1524f27ed164SFranco Fichtner static struct filterops netmap_kqfilter_ops = {
1525f27ed164SFranco Fichtner 	FILTEROP_ISFD, NULL, netmap_kqfilter_detach, netmap_kqfilter_event,
1526f27ed164SFranco Fichtner };
1527f27ed164SFranco Fichtner 
1528f27ed164SFranco Fichtner int
netmap_kqfilter(struct dev_kqfilter_args * ap)1529f27ed164SFranco Fichtner netmap_kqfilter(struct dev_kqfilter_args *ap)
1530f27ed164SFranco Fichtner {
1531f27ed164SFranco Fichtner 	struct knote *kn = ap->a_kn;
1532f27ed164SFranco Fichtner 
1533f27ed164SFranco Fichtner 	ap->a_result = 0;
1534f27ed164SFranco Fichtner 
1535f27ed164SFranco Fichtner 	switch (kn->kn_filter) {
1536f27ed164SFranco Fichtner 	case EVFILT_READ:
1537f27ed164SFranco Fichtner 	case EVFILT_WRITE:
1538f27ed164SFranco Fichtner 		kn->kn_fop = &netmap_kqfilter_ops;
1539f27ed164SFranco Fichtner 		break;
1540f27ed164SFranco Fichtner 	default:
1541f27ed164SFranco Fichtner 		ap->a_result = EOPNOTSUPP;
1542f27ed164SFranco Fichtner 		return (0);
1543f27ed164SFranco Fichtner 	}
1544f27ed164SFranco Fichtner 
1545f27ed164SFranco Fichtner 	return (0);
1546f27ed164SFranco Fichtner }
1547fb578518SFranco Fichtner 
1548fb578518SFranco Fichtner /*
1549fb578518SFranco Fichtner  * select(2) and poll(2) handlers for the "netmap" device.
1550fb578518SFranco Fichtner  *
1551fb578518SFranco Fichtner  * Can be called for one or more queues.
1552fb578518SFranco Fichtner  * Return true the event mask corresponding to ready events.
1553fb578518SFranco Fichtner  * If there are no ready events, do a selrecord on either individual
1554fb578518SFranco Fichtner  * selinfo or on the global one.
1555fb578518SFranco Fichtner  * Device-dependent parts (locking and sync of tx/rx rings)
1556fb578518SFranco Fichtner  * are done through callbacks.
1557fb578518SFranco Fichtner  *
1558fb578518SFranco Fichtner  * On linux, arguments are really pwait, the poll table, and 'td' is struct file *
1559fb578518SFranco Fichtner  * The first one is remapped to pwait as selrecord() uses the name as an
1560fb578518SFranco Fichtner  * hidden argument.
1561fb578518SFranco Fichtner  */
15623c0add62SFranco Fichtner static inline int	/* XXX mute unused for now */
netmap_poll(struct cdev * dev,int events,struct thread * td)1563fb578518SFranco Fichtner netmap_poll(struct cdev *dev, int events, struct thread *td)
1564fb578518SFranco Fichtner {
1565fb578518SFranco Fichtner 	struct netmap_priv_d *priv = NULL;
1566fb578518SFranco Fichtner 	struct netmap_adapter *na;
1567fb578518SFranco Fichtner 	struct ifnet *ifp;
1568fb578518SFranco Fichtner 	struct netmap_kring *kring;
1569fb578518SFranco Fichtner 	u_int i, check_all_tx, check_all_rx, want_tx, want_rx, revents = 0;
1570fb578518SFranco Fichtner 	u_int lim_tx, lim_rx, host_forwarded = 0;
1571fb578518SFranco Fichtner 	struct mbq q;
1572fb578518SFranco Fichtner 	void *pwait = dev;	/* linux compatibility */
1573fb578518SFranco Fichtner 
1574fb578518SFranco Fichtner 	/*
1575fb578518SFranco Fichtner 	 * In order to avoid nested locks, we need to "double check"
1576fb578518SFranco Fichtner 	 * txsync and rxsync if we decide to do a selrecord().
1577fb578518SFranco Fichtner 	 * retry_tx (and retry_rx, later) prevent looping forever.
1578fb578518SFranco Fichtner 	 */
1579fb578518SFranco Fichtner 	int retry_tx = 1;
1580fb578518SFranco Fichtner 
1581fb578518SFranco Fichtner 	(void)pwait;
1582fb578518SFranco Fichtner 	mbq_init(&q);
1583fb578518SFranco Fichtner 
15848b6c789bSFranco Fichtner 	/* XXX poll isn't ported yet so fill in NULL as a placeholder: */
15858b6c789bSFranco Fichtner 	if (devfs_get_cdevpriv(NULL, (void **)&priv) != 0 || priv == NULL)
15868b6c789bSFranco Fichtner 		return POLLERR;
1587fb578518SFranco Fichtner 
1588fb578518SFranco Fichtner 	if (priv->np_nifp == NULL) {
1589fb578518SFranco Fichtner 		D("No if registered");
1590fb578518SFranco Fichtner 		return POLLERR;
1591fb578518SFranco Fichtner 	}
1592fb578518SFranco Fichtner 	rmb(); /* make sure following reads are not from cache */
1593fb578518SFranco Fichtner 
1594fb578518SFranco Fichtner 	na = priv->np_na;
1595fb578518SFranco Fichtner 	ifp = na->ifp;
1596fb578518SFranco Fichtner 	// check for deleted
1597fb578518SFranco Fichtner 	if (ifp == NULL) {
1598fb578518SFranco Fichtner 		RD(1, "the ifp is gone");
1599fb578518SFranco Fichtner 		return POLLERR;
1600fb578518SFranco Fichtner 	}
1601fb578518SFranco Fichtner 
1602fb578518SFranco Fichtner 	if ( (ifp->if_capenable & IFCAP_NETMAP) == 0)
1603fb578518SFranco Fichtner 		return POLLERR;
1604fb578518SFranco Fichtner 
1605fb578518SFranco Fichtner 	if (netmap_verbose & 0x8000)
1606fb578518SFranco Fichtner 		D("device %s events 0x%x", NM_IFPNAME(ifp), events);
1607fb578518SFranco Fichtner 	want_tx = events & (POLLOUT | POLLWRNORM);
1608fb578518SFranco Fichtner 	want_rx = events & (POLLIN | POLLRDNORM);
1609fb578518SFranco Fichtner 
1610fb578518SFranco Fichtner 	lim_tx = na->num_tx_rings;
1611fb578518SFranco Fichtner 	lim_rx = na->num_rx_rings;
1612fb578518SFranco Fichtner 
1613fb578518SFranco Fichtner 	if (priv->np_qfirst == NETMAP_SW_RING) {
1614fb578518SFranco Fichtner 		/* handle the host stack ring */
1615fb578518SFranco Fichtner 		if (priv->np_txpoll || want_tx) {
1616fb578518SFranco Fichtner 			/* push any packets up, then we are always ready */
1617fb578518SFranco Fichtner 			netmap_txsync_to_host(na);
1618fb578518SFranco Fichtner 			revents |= want_tx;
1619fb578518SFranco Fichtner 		}
1620fb578518SFranco Fichtner 		if (want_rx) {
1621fb578518SFranco Fichtner 			kring = &na->rx_rings[lim_rx];
1622fb578518SFranco Fichtner 			if (kring->ring->avail == 0)
1623fb578518SFranco Fichtner 				netmap_rxsync_from_host(na, td, dev);
1624fb578518SFranco Fichtner 			if (kring->ring->avail > 0) {
1625fb578518SFranco Fichtner 				revents |= want_rx;
1626fb578518SFranco Fichtner 			}
1627fb578518SFranco Fichtner 		}
1628fb578518SFranco Fichtner 		return (revents);
1629fb578518SFranco Fichtner 	}
1630fb578518SFranco Fichtner 
1631fb578518SFranco Fichtner 	/*
1632fb578518SFranco Fichtner 	 * If we are in transparent mode, check also the host rx ring
1633fb578518SFranco Fichtner 	 * XXX Transparent mode at the moment requires to bind all
1634fb578518SFranco Fichtner  	 * rings to a single file descriptor.
1635fb578518SFranco Fichtner 	 */
1636fb578518SFranco Fichtner 	kring = &na->rx_rings[lim_rx];
1637fb578518SFranco Fichtner 	if ( (priv->np_qlast == NETMAP_HW_RING) // XXX check_all
1638fb578518SFranco Fichtner 			&& want_rx
1639fb578518SFranco Fichtner 			&& (netmap_fwd || kring->ring->flags & NR_FORWARD) ) {
1640fb578518SFranco Fichtner 		if (kring->ring->avail == 0)
1641fb578518SFranco Fichtner 			netmap_rxsync_from_host(na, td, dev);
1642fb578518SFranco Fichtner 		if (kring->ring->avail > 0)
1643fb578518SFranco Fichtner 			revents |= want_rx;
1644fb578518SFranco Fichtner 	}
1645fb578518SFranco Fichtner 
1646fb578518SFranco Fichtner 	/*
1647fb578518SFranco Fichtner 	 * check_all_{tx|rx} are set if the card has more than one queue AND
1648fb578518SFranco Fichtner 	 * the file descriptor is bound to all of them. If so, we sleep on
1649fb578518SFranco Fichtner 	 * the "global" selinfo, otherwise we sleep on individual selinfo
1650fb578518SFranco Fichtner 	 * (FreeBSD only allows two selinfo's per file descriptor).
1651fb578518SFranco Fichtner 	 * The interrupt routine in the driver wake one or the other
1652fb578518SFranco Fichtner 	 * (or both) depending on which clients are active.
1653fb578518SFranco Fichtner 	 *
1654fb578518SFranco Fichtner 	 * rxsync() is only called if we run out of buffers on a POLLIN.
1655fb578518SFranco Fichtner 	 * txsync() is called if we run out of buffers on POLLOUT, or
1656fb578518SFranco Fichtner 	 * there are pending packets to send. The latter can be disabled
1657fb578518SFranco Fichtner 	 * passing NETMAP_NO_TX_POLL in the NIOCREG call.
1658fb578518SFranco Fichtner 	 */
1659fb578518SFranco Fichtner 	check_all_tx = (priv->np_qlast == NETMAP_HW_RING) && (lim_tx > 1);
1660fb578518SFranco Fichtner 	check_all_rx = (priv->np_qlast == NETMAP_HW_RING) && (lim_rx > 1);
1661fb578518SFranco Fichtner 
1662fb578518SFranco Fichtner 	if (priv->np_qlast != NETMAP_HW_RING) {
1663fb578518SFranco Fichtner 		lim_tx = lim_rx = priv->np_qlast;
1664fb578518SFranco Fichtner 	}
1665fb578518SFranco Fichtner 
1666fb578518SFranco Fichtner 	/*
1667fb578518SFranco Fichtner 	 * We start with a lock free round which is cheap if we have
1668fb578518SFranco Fichtner 	 * slots available. If this fails, then lock and call the sync
1669fb578518SFranco Fichtner 	 * routines.
1670fb578518SFranco Fichtner 	 */
1671fb578518SFranco Fichtner 	for (i = priv->np_qfirst; want_rx && i < lim_rx; i++) {
1672fb578518SFranco Fichtner 		kring = &na->rx_rings[i];
1673fb578518SFranco Fichtner 		if (kring->ring->avail > 0) {
1674fb578518SFranco Fichtner 			revents |= want_rx;
1675fb578518SFranco Fichtner 			want_rx = 0;	/* also breaks the loop */
1676fb578518SFranco Fichtner 		}
1677fb578518SFranco Fichtner 	}
1678fb578518SFranco Fichtner 	for (i = priv->np_qfirst; want_tx && i < lim_tx; i++) {
1679fb578518SFranco Fichtner 		kring = &na->tx_rings[i];
1680fb578518SFranco Fichtner 		if (kring->ring->avail > 0) {
1681fb578518SFranco Fichtner 			revents |= want_tx;
1682fb578518SFranco Fichtner 			want_tx = 0;	/* also breaks the loop */
1683fb578518SFranco Fichtner 		}
1684fb578518SFranco Fichtner 	}
1685fb578518SFranco Fichtner 
1686fb578518SFranco Fichtner 	/*
1687fb578518SFranco Fichtner 	 * If we to push packets out (priv->np_txpoll) or want_tx is
1688fb578518SFranco Fichtner 	 * still set, we do need to run the txsync calls (on all rings,
1689fb578518SFranco Fichtner 	 * to avoid that the tx rings stall).
1690fb578518SFranco Fichtner 	 * XXX should also check cur != hwcur on the tx rings.
1691fb578518SFranco Fichtner 	 * Fortunately, normal tx mode has np_txpoll set.
1692fb578518SFranco Fichtner 	 */
1693fb578518SFranco Fichtner 	if (priv->np_txpoll || want_tx) {
1694fb578518SFranco Fichtner 		/* If we really want to be woken up (want_tx),
1695fb578518SFranco Fichtner 		 * do a selrecord, either on the global or on
1696fb578518SFranco Fichtner 		 * the private structure.  Then issue the txsync
1697fb578518SFranco Fichtner 		 * so there is no race in the selrecord/selwait
1698fb578518SFranco Fichtner 		 */
1699fb578518SFranco Fichtner flush_tx:
1700fb578518SFranco Fichtner 		for (i = priv->np_qfirst; i < lim_tx; i++) {
1701fb578518SFranco Fichtner 			kring = &na->tx_rings[i];
1702fb578518SFranco Fichtner 			/*
1703fb578518SFranco Fichtner 			 * Skip this ring if want_tx == 0
1704fb578518SFranco Fichtner 			 * (we have already done a successful sync on
1705fb578518SFranco Fichtner 			 * a previous ring) AND kring->cur == kring->hwcur
1706fb578518SFranco Fichtner 			 * (there are no pending transmissions for this ring).
1707fb578518SFranco Fichtner 			 */
1708fb578518SFranco Fichtner 			if (!want_tx && kring->ring->cur == kring->nr_hwcur)
1709fb578518SFranco Fichtner 				continue;
1710fb578518SFranco Fichtner 			/* make sure only one user thread is doing this */
1711fb578518SFranco Fichtner 			if (nm_kr_tryget(kring)) {
1712fb578518SFranco Fichtner 				ND("ring %p busy is %d",
1713fb578518SFranco Fichtner 				    kring, (int)kring->nr_busy);
1714fb578518SFranco Fichtner 				revents |= POLLERR;
1715fb578518SFranco Fichtner 				goto out;
1716fb578518SFranco Fichtner 			}
1717fb578518SFranco Fichtner 
1718fb578518SFranco Fichtner 			if (netmap_verbose & NM_VERB_TXSYNC)
1719fb578518SFranco Fichtner 				D("send %d on %s %d",
1720fb578518SFranco Fichtner 					kring->ring->cur, NM_IFPNAME(ifp), i);
1721fb578518SFranco Fichtner 			if (na->nm_txsync(na, i, 0))
1722fb578518SFranco Fichtner 				revents |= POLLERR;
1723fb578518SFranco Fichtner 
1724fb578518SFranco Fichtner 			/* Check avail/call selrecord only if called with POLLOUT */
1725fb578518SFranco Fichtner 			if (want_tx) {
1726fb578518SFranco Fichtner 				if (kring->ring->avail > 0) {
1727fb578518SFranco Fichtner 					/* stop at the first ring. We don't risk
1728fb578518SFranco Fichtner 					 * starvation.
1729fb578518SFranco Fichtner 					 */
1730fb578518SFranco Fichtner 					revents |= want_tx;
1731fb578518SFranco Fichtner 					want_tx = 0;
1732fb578518SFranco Fichtner 				}
1733fb578518SFranco Fichtner 			}
1734fb578518SFranco Fichtner 			nm_kr_put(kring);
1735fb578518SFranco Fichtner 		}
1736fb578518SFranco Fichtner 		if (want_tx && retry_tx) {
1737b3f97fadSFranco Fichtner 			KNOTE(check_all_tx ? &na->tx_si.ki_note :
1738b3f97fadSFranco Fichtner 			    &na->tx_rings[priv->np_qfirst].si.ki_note, 0);
1739fb578518SFranco Fichtner 			retry_tx = 0;
1740fb578518SFranco Fichtner 			goto flush_tx;
1741fb578518SFranco Fichtner 		}
1742fb578518SFranco Fichtner 	}
1743fb578518SFranco Fichtner 
1744fb578518SFranco Fichtner 	/*
1745fb578518SFranco Fichtner 	 * now if want_rx is still set we need to lock and rxsync.
1746fb578518SFranco Fichtner 	 * Do it on all rings because otherwise we starve.
1747fb578518SFranco Fichtner 	 */
1748fb578518SFranco Fichtner 	if (want_rx) {
1749fb578518SFranco Fichtner 		int retry_rx = 1;
1750fb578518SFranco Fichtner do_retry_rx:
1751fb578518SFranco Fichtner 		for (i = priv->np_qfirst; i < lim_rx; i++) {
1752fb578518SFranco Fichtner 			kring = &na->rx_rings[i];
1753fb578518SFranco Fichtner 
1754fb578518SFranco Fichtner 			if (nm_kr_tryget(kring)) {
1755fb578518SFranco Fichtner 				revents |= POLLERR;
1756fb578518SFranco Fichtner 				goto out;
1757fb578518SFranco Fichtner 			}
1758fb578518SFranco Fichtner 
1759fb578518SFranco Fichtner 			/* XXX NR_FORWARD should only be read on
1760fb578518SFranco Fichtner 			 * physical or NIC ports
1761fb578518SFranco Fichtner 			 */
1762fb578518SFranco Fichtner 			if (netmap_fwd ||kring->ring->flags & NR_FORWARD) {
1763fb578518SFranco Fichtner 				ND(10, "forwarding some buffers up %d to %d",
1764fb578518SFranco Fichtner 				    kring->nr_hwcur, kring->ring->cur);
1765fb578518SFranco Fichtner 				netmap_grab_packets(kring, &q, netmap_fwd);
1766fb578518SFranco Fichtner 			}
1767fb578518SFranco Fichtner 
1768fb578518SFranco Fichtner 			if (na->nm_rxsync(na, i, 0))
1769fb578518SFranco Fichtner 				revents |= POLLERR;
1770fb578518SFranco Fichtner 			if (netmap_no_timestamp == 0 ||
1771fb578518SFranco Fichtner 					kring->ring->flags & NR_TIMESTAMP) {
1772fb578518SFranco Fichtner 				microtime(&kring->ring->ts);
1773fb578518SFranco Fichtner 			}
1774fb578518SFranco Fichtner 
1775fb578518SFranco Fichtner 			if (kring->ring->avail > 0) {
1776fb578518SFranco Fichtner 				revents |= want_rx;
1777fb578518SFranco Fichtner 				retry_rx = 0;
1778fb578518SFranco Fichtner 			}
1779fb578518SFranco Fichtner 			nm_kr_put(kring);
1780fb578518SFranco Fichtner 		}
1781fb578518SFranco Fichtner 		if (retry_rx) {
1782fb578518SFranco Fichtner 			retry_rx = 0;
1783b3f97fadSFranco Fichtner 			KNOTE(check_all_rx ? &na->rx_si.ki_note :
1784b3f97fadSFranco Fichtner 			    &na->rx_rings[priv->np_qfirst].si.ki_note, 0);
1785fb578518SFranco Fichtner 			goto do_retry_rx;
1786fb578518SFranco Fichtner 		}
1787fb578518SFranco Fichtner 	}
1788fb578518SFranco Fichtner 
1789fb578518SFranco Fichtner 	/* forward host to the netmap ring.
1790fb578518SFranco Fichtner 	 * I am accessing nr_hwavail without lock, but netmap_transmit
1791fb578518SFranco Fichtner 	 * can only increment it, so the operation is safe.
1792fb578518SFranco Fichtner 	 */
1793fb578518SFranco Fichtner 	kring = &na->rx_rings[lim_rx];
1794fb578518SFranco Fichtner 	if ( (priv->np_qlast == NETMAP_HW_RING) // XXX check_all
1795fb578518SFranco Fichtner 			&& (netmap_fwd || kring->ring->flags & NR_FORWARD)
1796fb578518SFranco Fichtner 			 && kring->nr_hwavail > 0 && !host_forwarded) {
1797fb578518SFranco Fichtner 		netmap_sw_to_nic(na);
1798fb578518SFranco Fichtner 		host_forwarded = 1; /* prevent another pass */
1799fb578518SFranco Fichtner 		want_rx = 0;
1800fb578518SFranco Fichtner 		goto flush_tx;
1801fb578518SFranco Fichtner 	}
1802fb578518SFranco Fichtner 
1803fb578518SFranco Fichtner 	if (q.head)
1804fb578518SFranco Fichtner 		netmap_send_up(na->ifp, &q);
1805fb578518SFranco Fichtner 
1806fb578518SFranco Fichtner out:
1807fb578518SFranco Fichtner 
1808fb578518SFranco Fichtner 	return (revents);
1809fb578518SFranco Fichtner }
1810fb578518SFranco Fichtner 
1811fb578518SFranco Fichtner /*------- driver support routines ------*/
1812fb578518SFranco Fichtner 
1813fb578518SFranco Fichtner static int netmap_hw_krings_create(struct netmap_adapter *);
1814fb578518SFranco Fichtner 
1815fb578518SFranco Fichtner static int
netmap_notify(struct netmap_adapter * na,u_int n_ring,enum txrx tx,int flags)1816fb578518SFranco Fichtner netmap_notify(struct netmap_adapter *na, u_int n_ring, enum txrx tx, int flags)
1817fb578518SFranco Fichtner {
1818fb578518SFranco Fichtner 	struct netmap_kring *kring;
1819fb578518SFranco Fichtner 
1820fb578518SFranco Fichtner 	if (tx == NR_TX) {
1821fb578518SFranco Fichtner 		kring = na->tx_rings + n_ring;
1822f27ed164SFranco Fichtner 		KNOTE(&kring->si.ki_note, 0);
1823f27ed164SFranco Fichtner 		wakeup(&kring->si.ki_note);
1824fb578518SFranco Fichtner 		if (flags & NAF_GLOBAL_NOTIFY)
1825f27ed164SFranco Fichtner 			wakeup(&na->tx_si.ki_note);
1826fb578518SFranco Fichtner 	} else {
1827fb578518SFranco Fichtner 		kring = na->rx_rings + n_ring;
1828f27ed164SFranco Fichtner 		KNOTE(&kring->si.ki_note, 0);
1829f27ed164SFranco Fichtner 		wakeup(&kring->si.ki_note);
1830fb578518SFranco Fichtner 		if (flags & NAF_GLOBAL_NOTIFY)
1831f27ed164SFranco Fichtner 			wakeup(&na->rx_si.ki_note);
1832fb578518SFranco Fichtner 	}
1833fb578518SFranco Fichtner 	return 0;
1834fb578518SFranco Fichtner }
1835fb578518SFranco Fichtner 
1836fb578518SFranco Fichtner 
1837fb578518SFranco Fichtner // XXX check handling of failures
1838fb578518SFranco Fichtner int
netmap_attach_common(struct netmap_adapter * na)1839fb578518SFranco Fichtner netmap_attach_common(struct netmap_adapter *na)
1840fb578518SFranco Fichtner {
1841fb578518SFranco Fichtner 	struct ifnet *ifp = na->ifp;
1842fb578518SFranco Fichtner 
1843fb578518SFranco Fichtner 	if (na->num_tx_rings == 0 || na->num_rx_rings == 0) {
1844fb578518SFranco Fichtner 		D("%s: invalid rings tx %d rx %d",
1845fb578518SFranco Fichtner 			ifp->if_xname, na->num_tx_rings, na->num_rx_rings);
1846fb578518SFranco Fichtner 		return EINVAL;
1847fb578518SFranco Fichtner 	}
1848fb578518SFranco Fichtner 	WNA(ifp) = na;
1849fb578518SFranco Fichtner 	NETMAP_SET_CAPABLE(ifp);
1850fb578518SFranco Fichtner 	if (na->nm_krings_create == NULL) {
1851fb578518SFranco Fichtner 		na->nm_krings_create = netmap_hw_krings_create;
1852fb578518SFranco Fichtner 		na->nm_krings_delete = netmap_krings_delete;
1853fb578518SFranco Fichtner 	}
1854fb578518SFranco Fichtner 	if (na->nm_notify == NULL)
1855fb578518SFranco Fichtner 		na->nm_notify = netmap_notify;
1856fb578518SFranco Fichtner 	na->active_fds = 0;
1857fb578518SFranco Fichtner 
1858fb578518SFranco Fichtner 	if (na->nm_mem == NULL)
1859fb578518SFranco Fichtner 		na->nm_mem = &nm_mem;
1860fb578518SFranco Fichtner 	return 0;
1861fb578518SFranco Fichtner }
1862fb578518SFranco Fichtner 
1863fb578518SFranco Fichtner 
1864fb578518SFranco Fichtner void
netmap_detach_common(struct netmap_adapter * na)1865fb578518SFranco Fichtner netmap_detach_common(struct netmap_adapter *na)
1866fb578518SFranco Fichtner {
1867fb578518SFranco Fichtner 	if (na->ifp)
1868fb578518SFranco Fichtner 		WNA(na->ifp) = NULL; /* XXX do we need this? */
1869fb578518SFranco Fichtner 
1870fb578518SFranco Fichtner 	if (na->tx_rings) { /* XXX should not happen */
1871fb578518SFranco Fichtner 		D("freeing leftover tx_rings");
1872fb578518SFranco Fichtner 		na->nm_krings_delete(na);
1873fb578518SFranco Fichtner 	}
1874fb578518SFranco Fichtner 	if (na->na_flags & NAF_MEM_OWNER)
1875fb578518SFranco Fichtner 		netmap_mem_private_delete(na->nm_mem);
1876fb578518SFranco Fichtner 	bzero(na, sizeof(*na));
1877ed9bd855SFranco Fichtner 	kfree(na, M_DEVBUF);
1878fb578518SFranco Fichtner }
1879fb578518SFranco Fichtner 
1880fb578518SFranco Fichtner 
1881fb578518SFranco Fichtner /*
1882fb578518SFranco Fichtner  * Initialize a ``netmap_adapter`` object created by driver on attach.
1883fb578518SFranco Fichtner  * We allocate a block of memory with room for a struct netmap_adapter
1884fb578518SFranco Fichtner  * plus two sets of N+2 struct netmap_kring (where N is the number
1885fb578518SFranco Fichtner  * of hardware rings):
1886fb578518SFranco Fichtner  * krings	0..N-1	are for the hardware queues.
1887fb578518SFranco Fichtner  * kring	N	is for the host stack queue
1888fb578518SFranco Fichtner  * kring	N+1	is only used for the selinfo for all queues.
1889fb578518SFranco Fichtner  * Return 0 on success, ENOMEM otherwise.
1890fb578518SFranco Fichtner  *
1891fb578518SFranco Fichtner  * By default the receive and transmit adapter ring counts are both initialized
1892fb578518SFranco Fichtner  * to num_queues.  na->num_tx_rings can be set for cards with different tx/rx
1893fb578518SFranco Fichtner  * setups.
1894fb578518SFranco Fichtner  */
1895fb578518SFranco Fichtner int
netmap_attach(struct netmap_adapter * arg)1896fb578518SFranco Fichtner netmap_attach(struct netmap_adapter *arg)
1897fb578518SFranco Fichtner {
1898fb578518SFranco Fichtner 	struct netmap_hw_adapter *hwna = NULL;
1899fb578518SFranco Fichtner 	// XXX when is arg == NULL ?
1900fb578518SFranco Fichtner 	struct ifnet *ifp = arg ? arg->ifp : NULL;
1901fb578518SFranco Fichtner 
1902fb578518SFranco Fichtner 	if (arg == NULL || ifp == NULL)
1903fb578518SFranco Fichtner 		goto fail;
1904ed9bd855SFranco Fichtner 	hwna = kmalloc(sizeof(*hwna), M_DEVBUF, M_NOWAIT | M_ZERO);
1905fb578518SFranco Fichtner 	if (hwna == NULL)
1906fb578518SFranco Fichtner 		goto fail;
1907fb578518SFranco Fichtner 	hwna->up = *arg;
1908fb578518SFranco Fichtner 	if (netmap_attach_common(&hwna->up)) {
1909ed9bd855SFranco Fichtner 		kfree(hwna, M_DEVBUF);
1910fb578518SFranco Fichtner 		goto fail;
1911fb578518SFranco Fichtner 	}
1912fb578518SFranco Fichtner 	netmap_adapter_get(&hwna->up);
1913fb578518SFranco Fichtner 
1914fb578518SFranco Fichtner 	D("success for %s", NM_IFPNAME(ifp));
1915fb578518SFranco Fichtner 	return 0;
1916fb578518SFranco Fichtner 
1917fb578518SFranco Fichtner fail:
1918fb578518SFranco Fichtner 	D("fail, arg %p ifp %p na %p", arg, ifp, hwna);
1919fb578518SFranco Fichtner 	netmap_detach(ifp);
1920fb578518SFranco Fichtner 	return (hwna ? EINVAL : ENOMEM);
1921fb578518SFranco Fichtner }
1922fb578518SFranco Fichtner 
1923fb578518SFranco Fichtner 
1924fb578518SFranco Fichtner void
NM_DBG(netmap_adapter_get)1925fb578518SFranco Fichtner NM_DBG(netmap_adapter_get)(struct netmap_adapter *na)
1926fb578518SFranco Fichtner {
1927fb578518SFranco Fichtner 	if (!na) {
1928fb578518SFranco Fichtner 		return;
1929fb578518SFranco Fichtner 	}
1930fb578518SFranco Fichtner 
1931fb578518SFranco Fichtner 	refcount_acquire(&na->na_refcount);
1932fb578518SFranco Fichtner }
1933fb578518SFranco Fichtner 
1934fb578518SFranco Fichtner 
1935fb578518SFranco Fichtner /* returns 1 iff the netmap_adapter is destroyed */
1936fb578518SFranco Fichtner int
NM_DBG(netmap_adapter_put)1937fb578518SFranco Fichtner NM_DBG(netmap_adapter_put)(struct netmap_adapter *na)
1938fb578518SFranco Fichtner {
1939fb578518SFranco Fichtner 	if (!na)
1940fb578518SFranco Fichtner 		return 1;
1941fb578518SFranco Fichtner 
1942fb578518SFranco Fichtner 	if (!refcount_release(&na->na_refcount))
1943fb578518SFranco Fichtner 		return 0;
1944fb578518SFranco Fichtner 
1945fb578518SFranco Fichtner 	if (na->nm_dtor)
1946fb578518SFranco Fichtner 		na->nm_dtor(na);
1947fb578518SFranco Fichtner 
1948fb578518SFranco Fichtner 	netmap_detach_common(na);
1949fb578518SFranco Fichtner 
1950fb578518SFranco Fichtner 	return 1;
1951fb578518SFranco Fichtner }
1952fb578518SFranco Fichtner 
1953fb578518SFranco Fichtner 
1954fb578518SFranco Fichtner int
netmap_hw_krings_create(struct netmap_adapter * na)1955fb578518SFranco Fichtner netmap_hw_krings_create(struct netmap_adapter *na)
1956fb578518SFranco Fichtner {
1957fb578518SFranco Fichtner 	return netmap_krings_create(na,
1958fb578518SFranco Fichtner 		na->num_tx_rings + 1, na->num_rx_rings + 1, 0);
1959fb578518SFranco Fichtner }
1960fb578518SFranco Fichtner 
1961fb578518SFranco Fichtner 
1962fb578518SFranco Fichtner 
1963fb578518SFranco Fichtner /*
1964fb578518SFranco Fichtner  * Free the allocated memory linked to the given ``netmap_adapter``
1965fb578518SFranco Fichtner  * object.
1966fb578518SFranco Fichtner  */
1967fb578518SFranco Fichtner void
netmap_detach(struct ifnet * ifp)1968fb578518SFranco Fichtner netmap_detach(struct ifnet *ifp)
1969fb578518SFranco Fichtner {
1970fb578518SFranco Fichtner 	struct netmap_adapter *na = NA(ifp);
1971fb578518SFranco Fichtner 
1972fb578518SFranco Fichtner 	if (!na)
1973fb578518SFranco Fichtner 		return;
1974fb578518SFranco Fichtner 
1975fb578518SFranco Fichtner 	NMG_LOCK();
1976fb578518SFranco Fichtner 	netmap_disable_all_rings(ifp);
1977fb578518SFranco Fichtner 	netmap_adapter_put(na);
1978fb578518SFranco Fichtner 	na->ifp = NULL;
1979fb578518SFranco Fichtner 	netmap_enable_all_rings(ifp);
1980fb578518SFranco Fichtner 	NMG_UNLOCK();
1981fb578518SFranco Fichtner }
1982fb578518SFranco Fichtner 
1983fb578518SFranco Fichtner 
1984fb578518SFranco Fichtner /*
1985fb578518SFranco Fichtner  * Intercept packets from the network stack and pass them
1986fb578518SFranco Fichtner  * to netmap as incoming packets on the 'software' ring.
1987fb578518SFranco Fichtner  * We rely on the OS to make sure that the ifp and na do not go
1988fb578518SFranco Fichtner  * away (typically the caller checks for IFF_DRV_RUNNING or the like).
1989fb578518SFranco Fichtner  * In nm_register() or whenever there is a reinitialization,
1990fb578518SFranco Fichtner  * we make sure to access the core lock and per-ring locks
1991fb578518SFranco Fichtner  * so that IFCAP_NETMAP is visible here.
1992fb578518SFranco Fichtner  */
1993fb578518SFranco Fichtner int
netmap_transmit(struct ifnet * ifp,struct mbuf * m)1994fb578518SFranco Fichtner netmap_transmit(struct ifnet *ifp, struct mbuf *m)
1995fb578518SFranco Fichtner {
1996fb578518SFranco Fichtner 	struct netmap_adapter *na = NA(ifp);
1997fb578518SFranco Fichtner 	struct netmap_kring *kring;
1998fb578518SFranco Fichtner 	u_int i, len = MBUF_LEN(m);
1999fb578518SFranco Fichtner 	u_int error = EBUSY, lim;
2000fb578518SFranco Fichtner 	struct netmap_slot *slot;
2001fb578518SFranco Fichtner 
2002fb578518SFranco Fichtner 	// XXX [Linux] we do not need this lock
2003fb578518SFranco Fichtner 	// if we follow the down/configure/up protocol -gl
2004fb578518SFranco Fichtner 	// mtx_lock(&na->core_lock);
2005fb578518SFranco Fichtner 	if ( (ifp->if_capenable & IFCAP_NETMAP) == 0) {
2006fb578518SFranco Fichtner 		/* interface not in netmap mode anymore */
2007fb578518SFranco Fichtner 		error = ENXIO;
2008fb578518SFranco Fichtner 		goto done;
2009fb578518SFranco Fichtner 	}
2010fb578518SFranco Fichtner 
2011fb578518SFranco Fichtner 	kring = &na->rx_rings[na->num_rx_rings];
2012fb578518SFranco Fichtner 	lim = kring->nkr_num_slots - 1;
2013fb578518SFranco Fichtner 	if (netmap_verbose & NM_VERB_HOST)
2014fb578518SFranco Fichtner 		D("%s packet %d len %d from the stack", NM_IFPNAME(ifp),
2015fb578518SFranco Fichtner 			kring->nr_hwcur + kring->nr_hwavail, len);
2016fb578518SFranco Fichtner 	// XXX reconsider long packets if we handle fragments
2017fb578518SFranco Fichtner 	if (len > NETMAP_BDG_BUF_SIZE(na->nm_mem)) { /* too long for us */
2018fb578518SFranco Fichtner 		D("%s from_host, drop packet size %d > %d", NM_IFPNAME(ifp),
2019fb578518SFranco Fichtner 			len, NETMAP_BDG_BUF_SIZE(na->nm_mem));
2020fb578518SFranco Fichtner 		goto done;
2021fb578518SFranco Fichtner 	}
2022fb578518SFranco Fichtner 	/* protect against other instances of netmap_transmit,
2023fb578518SFranco Fichtner 	 * and userspace invocations of rxsync().
2024fb578518SFranco Fichtner 	 */
2025fb578518SFranco Fichtner 	// XXX [Linux] there can be no other instances of netmap_transmit
2026fb578518SFranco Fichtner 	// on this same ring, but we still need this lock to protect
2027fb578518SFranco Fichtner 	// concurrent access from netmap_sw_to_nic() -gl
2028ed9bd855SFranco Fichtner 	lockmgr(&kring->q_lock, LK_EXCLUSIVE);
2029fb578518SFranco Fichtner 	if (kring->nr_hwavail >= lim) {
2030fb578518SFranco Fichtner 		if (netmap_verbose)
2031fb578518SFranco Fichtner 			D("stack ring %s full\n", NM_IFPNAME(ifp));
2032fb578518SFranco Fichtner 	} else {
2033fb578518SFranco Fichtner 		/* compute the insert position */
2034fb578518SFranco Fichtner 		i = nm_kr_rxpos(kring);
2035fb578518SFranco Fichtner 		slot = &kring->ring->slot[i];
2036fb578518SFranco Fichtner 		m_copydata(m, 0, (int)len, BDG_NMB(na, slot));
2037fb578518SFranco Fichtner 		slot->len = len;
2038fb578518SFranco Fichtner 		slot->flags = kring->nkr_slot_flags;
2039fb578518SFranco Fichtner 		kring->nr_hwavail++;
2040fb578518SFranco Fichtner 		if (netmap_verbose  & NM_VERB_HOST)
2041fb578518SFranco Fichtner 			D("wake up host ring %s %d", NM_IFPNAME(na->ifp), na->num_rx_rings);
2042fb578518SFranco Fichtner 		na->nm_notify(na, na->num_rx_rings, NR_RX, 0);
2043fb578518SFranco Fichtner 		error = 0;
2044fb578518SFranco Fichtner 	}
2045ed9bd855SFranco Fichtner 	lockmgr(&kring->q_lock, LK_RELEASE);
2046fb578518SFranco Fichtner 
2047fb578518SFranco Fichtner done:
2048fb578518SFranco Fichtner 	// mtx_unlock(&na->core_lock);
2049fb578518SFranco Fichtner 
2050fb578518SFranco Fichtner 	/* release the mbuf in either cases of success or failure. As an
2051fb578518SFranco Fichtner 	 * alternative, put the mbuf in a free list and free the list
2052fb578518SFranco Fichtner 	 * only when really necessary.
2053fb578518SFranco Fichtner 	 */
2054fb578518SFranco Fichtner 	m_freem(m);
2055fb578518SFranco Fichtner 
2056fb578518SFranco Fichtner 	return (error);
2057fb578518SFranco Fichtner }
2058fb578518SFranco Fichtner 
2059fb578518SFranco Fichtner 
2060fb578518SFranco Fichtner /*
2061fb578518SFranco Fichtner  * netmap_reset() is called by the driver routines when reinitializing
2062fb578518SFranco Fichtner  * a ring. The driver is in charge of locking to protect the kring.
2063fb578518SFranco Fichtner  * If native netmap mode is not set just return NULL.
2064fb578518SFranco Fichtner  */
2065fb578518SFranco Fichtner struct netmap_slot *
netmap_reset(struct netmap_adapter * na,enum txrx tx,u_int n,u_int new_cur)2066fb578518SFranco Fichtner netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n,
2067fb578518SFranco Fichtner 	u_int new_cur)
2068fb578518SFranco Fichtner {
2069fb578518SFranco Fichtner 	struct netmap_kring *kring;
2070fb578518SFranco Fichtner 	int new_hwofs, lim;
2071fb578518SFranco Fichtner 
2072fb578518SFranco Fichtner 	if (na == NULL) {
2073fb578518SFranco Fichtner 		D("NULL na, should not happen");
2074fb578518SFranco Fichtner 		return NULL;	/* no netmap support here */
2075fb578518SFranco Fichtner 	}
2076fb578518SFranco Fichtner 	if (!(na->ifp->if_capenable & IFCAP_NETMAP) || nma_is_generic(na)) {
2077fb578518SFranco Fichtner 		ND("interface not in netmap mode");
2078fb578518SFranco Fichtner 		return NULL;	/* nothing to reinitialize */
2079fb578518SFranco Fichtner 	}
2080fb578518SFranco Fichtner 
2081fb578518SFranco Fichtner 	/* XXX note- in the new scheme, we are not guaranteed to be
2082fb578518SFranco Fichtner 	 * under lock (e.g. when called on a device reset).
2083fb578518SFranco Fichtner 	 * In this case, we should set a flag and do not trust too
2084fb578518SFranco Fichtner 	 * much the values. In practice: TODO
2085fb578518SFranco Fichtner 	 * - set a RESET flag somewhere in the kring
2086fb578518SFranco Fichtner 	 * - do the processing in a conservative way
2087fb578518SFranco Fichtner 	 * - let the *sync() fixup at the end.
2088fb578518SFranco Fichtner 	 */
2089fb578518SFranco Fichtner 	if (tx == NR_TX) {
2090fb578518SFranco Fichtner 		if (n >= na->num_tx_rings)
2091fb578518SFranco Fichtner 			return NULL;
2092fb578518SFranco Fichtner 		kring = na->tx_rings + n;
2093fb578518SFranco Fichtner 		new_hwofs = kring->nr_hwcur - new_cur;
2094fb578518SFranco Fichtner 	} else {
2095fb578518SFranco Fichtner 		if (n >= na->num_rx_rings)
2096fb578518SFranco Fichtner 			return NULL;
2097fb578518SFranco Fichtner 		kring = na->rx_rings + n;
2098fb578518SFranco Fichtner 		new_hwofs = kring->nr_hwcur + kring->nr_hwavail - new_cur;
2099fb578518SFranco Fichtner 	}
2100fb578518SFranco Fichtner 	lim = kring->nkr_num_slots - 1;
2101fb578518SFranco Fichtner 	if (new_hwofs > lim)
2102fb578518SFranco Fichtner 		new_hwofs -= lim + 1;
2103fb578518SFranco Fichtner 
2104fb578518SFranco Fichtner 	/* Always set the new offset value and realign the ring. */
2105fb578518SFranco Fichtner 	D("%s hwofs %d -> %d, hwavail %d -> %d",
2106fb578518SFranco Fichtner 		tx == NR_TX ? "TX" : "RX",
2107fb578518SFranco Fichtner 		kring->nkr_hwofs, new_hwofs,
2108fb578518SFranco Fichtner 		kring->nr_hwavail,
2109fb578518SFranco Fichtner 		tx == NR_TX ? lim : kring->nr_hwavail);
2110fb578518SFranco Fichtner 	kring->nkr_hwofs = new_hwofs;
2111fb578518SFranco Fichtner 	if (tx == NR_TX)
2112fb578518SFranco Fichtner 		kring->nr_hwavail = lim;
2113fb578518SFranco Fichtner 	kring->nr_hwreserved = 0;
2114fb578518SFranco Fichtner 
2115fb578518SFranco Fichtner 	/*
2116fb578518SFranco Fichtner 	 * Wakeup on the individual and global selwait
2117fb578518SFranco Fichtner 	 * We do the wakeup here, but the ring is not yet reconfigured.
2118fb578518SFranco Fichtner 	 * However, we are under lock so there are no races.
2119fb578518SFranco Fichtner 	 */
2120fb578518SFranco Fichtner 	na->nm_notify(na, n, tx, NAF_GLOBAL_NOTIFY);
2121fb578518SFranco Fichtner 	return kring->ring->slot;
2122fb578518SFranco Fichtner }
2123fb578518SFranco Fichtner 
2124fb578518SFranco Fichtner 
2125fb578518SFranco Fichtner /*
2126fb578518SFranco Fichtner  * Default functions to handle rx/tx interrupts from a physical device.
2127fb578518SFranco Fichtner  * "work_done" is non-null on the RX path, NULL for the TX path.
2128fb578518SFranco Fichtner  * "generic" is 0 when we are called by a device driver, and 1 when we
2129fb578518SFranco Fichtner  * are called by the generic netmap adapter layer.
2130fb578518SFranco Fichtner  * We rely on the OS to make sure that there is only one active
2131fb578518SFranco Fichtner  * instance per queue, and that there is appropriate locking.
2132fb578518SFranco Fichtner  *
2133fb578518SFranco Fichtner  * If the card is not in netmap mode, simply return 0,
2134fb578518SFranco Fichtner  * so that the caller proceeds with regular processing.
2135fb578518SFranco Fichtner  *
2136fb578518SFranco Fichtner  * We return 0 also when the card is in netmap mode but the current
2137fb578518SFranco Fichtner  * netmap adapter is the generic one, because this function will be
2138fb578518SFranco Fichtner  * called by the generic layer.
2139fb578518SFranco Fichtner  *
2140fb578518SFranco Fichtner  * If the card is connected to a netmap file descriptor,
2141fb578518SFranco Fichtner  * do a selwakeup on the individual queue, plus one on the global one
2142fb578518SFranco Fichtner  * if needed (multiqueue card _and_ there are multiqueue listeners),
2143fb578518SFranco Fichtner  * and return 1.
2144fb578518SFranco Fichtner  *
2145fb578518SFranco Fichtner  * Finally, if called on rx from an interface connected to a switch,
2146fb578518SFranco Fichtner  * calls the proper forwarding routine, and return 1.
2147fb578518SFranco Fichtner  */
2148fb578518SFranco Fichtner int
netmap_common_irq(struct ifnet * ifp,u_int q,u_int * work_done)2149fb578518SFranco Fichtner netmap_common_irq(struct ifnet *ifp, u_int q, u_int *work_done)
2150fb578518SFranco Fichtner {
2151fb578518SFranco Fichtner 	struct netmap_adapter *na = NA(ifp);
2152fb578518SFranco Fichtner 	struct netmap_kring *kring;
2153fb578518SFranco Fichtner 
2154fb578518SFranco Fichtner 	q &= NETMAP_RING_MASK;
2155fb578518SFranco Fichtner 
2156fb578518SFranco Fichtner 	if (netmap_verbose) {
2157fb578518SFranco Fichtner 	        RD(5, "received %s queue %d", work_done ? "RX" : "TX" , q);
2158fb578518SFranco Fichtner 	}
2159fb578518SFranco Fichtner 
2160fb578518SFranco Fichtner 	if (work_done) { /* RX path */
2161fb578518SFranco Fichtner 		if (q >= na->num_rx_rings)
2162fb578518SFranco Fichtner 			return 0;	// not a physical queue
2163fb578518SFranco Fichtner 		kring = na->rx_rings + q;
2164fb578518SFranco Fichtner 		kring->nr_kflags |= NKR_PENDINTR;	// XXX atomic ?
2165fb578518SFranco Fichtner 		na->nm_notify(na, q, NR_RX,
2166fb578518SFranco Fichtner 			(na->num_rx_rings > 1 ? NAF_GLOBAL_NOTIFY : 0));
2167fb578518SFranco Fichtner 		*work_done = 1; /* do not fire napi again */
2168fb578518SFranco Fichtner 	} else { /* TX path */
2169fb578518SFranco Fichtner 		if (q >= na->num_tx_rings)
2170fb578518SFranco Fichtner 			return 0;	// not a physical queue
2171fb578518SFranco Fichtner 		kring = na->tx_rings + q;
2172fb578518SFranco Fichtner 		na->nm_notify(na, q, NR_TX,
2173fb578518SFranco Fichtner 			(na->num_tx_rings > 1 ? NAF_GLOBAL_NOTIFY : 0));
2174fb578518SFranco Fichtner 	}
2175fb578518SFranco Fichtner 	return 1;
2176fb578518SFranco Fichtner }
2177fb578518SFranco Fichtner 
2178fb578518SFranco Fichtner /*
2179fb578518SFranco Fichtner  * Default functions to handle rx/tx interrupts from a physical device.
2180fb578518SFranco Fichtner  * "work_done" is non-null on the RX path, NULL for the TX path.
2181fb578518SFranco Fichtner  * "generic" is 0 when we are called by a device driver, and 1 when we
2182fb578518SFranco Fichtner  * are called by the generic netmap adapter layer.
2183fb578518SFranco Fichtner  * We rely on the OS to make sure that there is only one active
2184fb578518SFranco Fichtner  * instance per queue, and that there is appropriate locking.
2185fb578518SFranco Fichtner  *
2186fb578518SFranco Fichtner  * If the card is not in netmap mode, simply return 0,
2187fb578518SFranco Fichtner  * so that the caller proceeds with regular processing.
2188fb578518SFranco Fichtner  *
2189fb578518SFranco Fichtner  * If the card is connected to a netmap file descriptor,
2190fb578518SFranco Fichtner  * do a selwakeup on the individual queue, plus one on the global one
2191fb578518SFranco Fichtner  * if needed (multiqueue card _and_ there are multiqueue listeners),
2192fb578518SFranco Fichtner  * and return 1.
2193fb578518SFranco Fichtner  *
2194fb578518SFranco Fichtner  * Finally, if called on rx from an interface connected to a switch,
2195fb578518SFranco Fichtner  * calls the proper forwarding routine, and return 1.
2196fb578518SFranco Fichtner  */
2197fb578518SFranco Fichtner int
netmap_rx_irq(struct ifnet * ifp,u_int q,u_int * work_done)2198fb578518SFranco Fichtner netmap_rx_irq(struct ifnet *ifp, u_int q, u_int *work_done)
2199fb578518SFranco Fichtner {
2200fb578518SFranco Fichtner 	// XXX could we check NAF_NATIVE_ON ?
2201fb578518SFranco Fichtner 	if (!(ifp->if_capenable & IFCAP_NETMAP))
2202fb578518SFranco Fichtner 		return 0;
2203fb578518SFranco Fichtner 
2204fb578518SFranco Fichtner 	if (NA(ifp)->na_flags & NAF_SKIP_INTR) {
2205fb578518SFranco Fichtner 		ND("use regular interrupt");
2206fb578518SFranco Fichtner 		return 0;
2207fb578518SFranco Fichtner 	}
2208fb578518SFranco Fichtner 
2209fb578518SFranco Fichtner 	return netmap_common_irq(ifp, q, work_done);
2210fb578518SFranco Fichtner }
2211fb578518SFranco Fichtner 
2212fb578518SFranco Fichtner 
2213fb578518SFranco Fichtner static struct cdev *netmap_dev; /* /dev/netmap character device. */
2214fb578518SFranco Fichtner 
2215fb578518SFranco Fichtner 
2216fb578518SFranco Fichtner /*
2217fb578518SFranco Fichtner  * Module loader.
2218fb578518SFranco Fichtner  *
2219fb578518SFranco Fichtner  * Create the /dev/netmap device and initialize all global
2220fb578518SFranco Fichtner  * variables.
2221fb578518SFranco Fichtner  *
2222fb578518SFranco Fichtner  * Return 0 on success, errno on failure.
2223fb578518SFranco Fichtner  */
2224fb578518SFranco Fichtner int
netmap_init(void)2225fb578518SFranco Fichtner netmap_init(void)
2226fb578518SFranco Fichtner {
2227fb578518SFranco Fichtner 	int error;
2228fb578518SFranco Fichtner 
2229fb578518SFranco Fichtner 	NMG_LOCK_INIT();
2230fb578518SFranco Fichtner 
2231fb578518SFranco Fichtner 	error = netmap_mem_init();
2232fb578518SFranco Fichtner 	if (error != 0) {
2233ed9bd855SFranco Fichtner 		kprintf("netmap: unable to initialize the memory allocator.\n");
2234fb578518SFranco Fichtner 		return (error);
2235fb578518SFranco Fichtner 	}
2236ed9bd855SFranco Fichtner 	kprintf("netmap: loaded module\n");
2237fb578518SFranco Fichtner 	netmap_dev = make_dev(&netmap_cdevsw, 0, UID_ROOT, GID_WHEEL, 0660,
2238fb578518SFranco Fichtner 			      "netmap");
2239fb578518SFranco Fichtner 
2240fb578518SFranco Fichtner 	netmap_init_bridges();
2241fb578518SFranco Fichtner 	return (error);
2242fb578518SFranco Fichtner }
2243fb578518SFranco Fichtner 
2244fb578518SFranco Fichtner 
2245fb578518SFranco Fichtner /*
2246fb578518SFranco Fichtner  * Module unloader.
2247fb578518SFranco Fichtner  *
2248fb578518SFranco Fichtner  * Free all the memory, and destroy the ``/dev/netmap`` device.
2249fb578518SFranco Fichtner  */
2250fb578518SFranco Fichtner void
netmap_fini(void)2251fb578518SFranco Fichtner netmap_fini(void)
2252fb578518SFranco Fichtner {
2253fb578518SFranco Fichtner 	destroy_dev(netmap_dev);
2254fb578518SFranco Fichtner 	netmap_mem_fini();
2255fb578518SFranco Fichtner 	NMG_LOCK_DESTROY();
2256ed9bd855SFranco Fichtner 	kprintf("netmap: unloaded module.\n");
2257fb578518SFranco Fichtner }
2258