xref: /dflybsd-src/sys/net/netmap/netmap_freebsd.c (revision 44647b48cc48ca54dc839a0c8652cd4960416c2b)
1fb578518SFranco Fichtner /*
2fb578518SFranco Fichtner  * Copyright (C) 2013 Universita` di Pisa. 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 #include <sys/types.h>
27fb578518SFranco Fichtner #include <sys/module.h>
28fb578518SFranco Fichtner #include <sys/errno.h>
29fb578518SFranco Fichtner #include <sys/param.h>  /* defines used in kernel.h */
30fb578518SFranco Fichtner #include <sys/kernel.h> /* types used in module initialization */
31fb578518SFranco Fichtner #include <sys/conf.h>	/* DEV_MODULE */
32785c7ee6SFranco Fichtner 
3313431b3eSFranco Fichtner #include <sys/devfs.h>
34fb578518SFranco Fichtner 
35fb578518SFranco Fichtner #include <vm/vm.h>      /* vtophys */
36fb578518SFranco Fichtner #include <vm/pmap.h>    /* vtophys */
37fb578518SFranco Fichtner #include <vm/vm_param.h>
38fb578518SFranco Fichtner #include <vm/vm_object.h>
39fb578518SFranco Fichtner #include <vm/vm_page.h>
40bf9f7c16SFranco Fichtner #include <vm/vm_page2.h>
41fb578518SFranco Fichtner #include <vm/vm_pager.h>
42fb578518SFranco Fichtner 
4313431b3eSFranco Fichtner 
4413431b3eSFranco Fichtner #include <sys/malloc.h>
4513431b3eSFranco Fichtner #include <sys/socket.h> /* sockaddrs */
4613431b3eSFranco Fichtner #include <sys/event.h>
47fb578518SFranco Fichtner #include <net/if.h>
48fb578518SFranco Fichtner #include <net/if_var.h>
491d53fdceSFranco Fichtner #include <net/ifq_var.h>
5013431b3eSFranco Fichtner #include <sys/bus.h>	/* bus_dmamap_* */
51ed9bd855SFranco Fichtner 
52f933b737SSascha Wildner #include <net/netmap/netmap.h>
53b3f97fadSFranco Fichtner #include <net/netmap/netmap_kern.h>
54b3f97fadSFranco Fichtner #include <net/netmap/netmap_mem2.h>
55fb578518SFranco Fichtner 
56fb578518SFranco Fichtner 
57fb578518SFranco Fichtner /* ======================== FREEBSD-SPECIFIC ROUTINES ================== */
58fb578518SFranco Fichtner 
59fb578518SFranco Fichtner /*
60fb578518SFranco Fichtner  * Intercept the rx routine in the standard device driver.
61fb578518SFranco Fichtner  * Second argument is non-zero to intercept, 0 to restore
62fb578518SFranco Fichtner  */
63fb578518SFranco Fichtner int
netmap_catch_rx(struct netmap_adapter * na,int intercept)64fb578518SFranco Fichtner netmap_catch_rx(struct netmap_adapter *na, int intercept)
65fb578518SFranco Fichtner {
66fb578518SFranco Fichtner 	struct netmap_generic_adapter *gna = (struct netmap_generic_adapter *)na;
67fb578518SFranco Fichtner 	struct ifnet *ifp = na->ifp;
68fb578518SFranco Fichtner 
69fb578518SFranco Fichtner 	if (intercept) {
70fb578518SFranco Fichtner 		if (gna->save_if_input) {
71fb578518SFranco Fichtner 			D("cannot intercept again");
72fb578518SFranco Fichtner 			return EINVAL; /* already set */
73fb578518SFranco Fichtner 		}
74fb578518SFranco Fichtner 		gna->save_if_input = ifp->if_input;
75fb578518SFranco Fichtner 		ifp->if_input = generic_rx_handler;
76fb578518SFranco Fichtner 	} else {
77fb578518SFranco Fichtner 		if (!gna->save_if_input){
78fb578518SFranco Fichtner 			D("cannot restore");
79fb578518SFranco Fichtner 			return EINVAL;  /* not saved */
80fb578518SFranco Fichtner 		}
81fb578518SFranco Fichtner 		ifp->if_input = gna->save_if_input;
82fb578518SFranco Fichtner 		gna->save_if_input = NULL;
83fb578518SFranco Fichtner 	}
84fb578518SFranco Fichtner 
85fb578518SFranco Fichtner 	return 0;
86fb578518SFranco Fichtner }
87fb578518SFranco Fichtner 
88fb578518SFranco Fichtner /*
89fb578518SFranco Fichtner  * Intercept the packet steering routine in the tx path,
90fb578518SFranco Fichtner  * so that we can decide which queue is used for an mbuf.
91fb578518SFranco Fichtner  * Second argument is non-zero to intercept, 0 to restore.
92fb578518SFranco Fichtner  *
93fb578518SFranco Fichtner  * XXX see if FreeBSD has such a mechanism
94fb578518SFranco Fichtner  */
95fb578518SFranco Fichtner void
netmap_catch_packet_steering(struct netmap_generic_adapter * na,int enable)96fb578518SFranco Fichtner netmap_catch_packet_steering(struct netmap_generic_adapter *na, int enable)
97fb578518SFranco Fichtner {
98fb578518SFranco Fichtner 	if (enable) {
99fb578518SFranco Fichtner 	} else {
100fb578518SFranco Fichtner 	}
101fb578518SFranco Fichtner }
102fb578518SFranco Fichtner 
103fb578518SFranco Fichtner /* Transmit routine used by generic_netmap_txsync(). Returns 0 on success
104fb578518SFranco Fichtner  * and non-zero on error (which may be packet drops or other errors).
105fb578518SFranco Fichtner  * addr and len identify the netmap buffer, m is the (preallocated)
106fb578518SFranco Fichtner  * mbuf to use for transmissions.
107fb578518SFranco Fichtner  *
108fb578518SFranco Fichtner  * We should add a reference to the mbuf so the m_freem() at the end
109fb578518SFranco Fichtner  * of the transmission does not consume resources.
110fb578518SFranco Fichtner  *
111fb578518SFranco Fichtner  * On FreeBSD, and on multiqueue cards, we can force the queue using
112fb578518SFranco Fichtner  *      if ((m->m_flags & M_FLOWID) != 0)
113fb578518SFranco Fichtner  *              i = m->m_pkthdr.flowid % adapter->num_queues;
114fb578518SFranco Fichtner  *      else
115fb578518SFranco Fichtner  *              i = curcpu % adapter->num_queues;
116fb578518SFranco Fichtner  *
117fb578518SFranco Fichtner  */
118fb578518SFranco Fichtner int
generic_xmit_frame(struct ifnet * ifp,struct mbuf * m,void * addr,u_int len,u_int ring_nr)119fb578518SFranco Fichtner generic_xmit_frame(struct ifnet *ifp, struct mbuf *m,
120fb578518SFranco Fichtner 	void *addr, u_int len, u_int ring_nr)
121fb578518SFranco Fichtner {
122fb578518SFranco Fichtner 	int ret;
123fb578518SFranco Fichtner 
124fb578518SFranco Fichtner 	m->m_len = m->m_pkthdr.len = 0;
125fb578518SFranco Fichtner 
126fb578518SFranco Fichtner 	// copy data to the mbuf
127*44647b48SAaron LI 	ret = m_copyback2(m, 0, len, addr, M_NOWAIT);
128*44647b48SAaron LI 	if (ret != 0)
129*44647b48SAaron LI 		return ret;
130fb578518SFranco Fichtner 
131bf9f7c16SFranco Fichtner #if 0
132fb578518SFranco Fichtner 	// inc refcount. We are alone, so we can skip the atomic
133fb578518SFranco Fichtner 	atomic_fetchadd_int(m->m_ext.ref_cnt, 1);
134fb578518SFranco Fichtner 	m->m_flags |= M_FLOWID;
135bf9f7c16SFranco Fichtner #endif
136bf9f7c16SFranco Fichtner 	m->m_pkthdr.hash = ring_nr;	/* XXX probably not accurate */
137fb578518SFranco Fichtner 	m->m_pkthdr.rcvif = ifp; /* used for tx notification */
1381d53fdceSFranco Fichtner 	ret = ifq_dispatch(ifp, m, NULL);
139fb578518SFranco Fichtner 	return ret;
140fb578518SFranco Fichtner }
141fb578518SFranco Fichtner 
142fb578518SFranco Fichtner /*
143fb578518SFranco Fichtner  * The following two functions are empty until we have a generic
144fb578518SFranco Fichtner  * way to extract the info from the ifp
145fb578518SFranco Fichtner  */
146fb578518SFranco Fichtner int
generic_find_num_desc(struct ifnet * ifp,unsigned int * tx,unsigned int * rx)147fb578518SFranco Fichtner generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *rx)
148fb578518SFranco Fichtner {
149fb578518SFranco Fichtner 	D("called");
150fb578518SFranco Fichtner 	return 0;
151fb578518SFranco Fichtner }
152fb578518SFranco Fichtner 
153fb578518SFranco Fichtner void
generic_find_num_queues(struct ifnet * ifp,u_int * txq,u_int * rxq)154fb578518SFranco Fichtner generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq)
155fb578518SFranco Fichtner {
156fb578518SFranco Fichtner 	D("called");
157fb578518SFranco Fichtner 	*txq = 1;
158fb578518SFranco Fichtner 	*rxq = 1;
159fb578518SFranco Fichtner }
160fb578518SFranco Fichtner 
netmap_mitigation_init(struct netmap_generic_adapter * na)161fb578518SFranco Fichtner void netmap_mitigation_init(struct netmap_generic_adapter *na)
162fb578518SFranco Fichtner {
163fb578518SFranco Fichtner 	ND("called");
164fb578518SFranco Fichtner 	na->mit_pending = 0;
165fb578518SFranco Fichtner }
166fb578518SFranco Fichtner 
167fb578518SFranco Fichtner 
netmap_mitigation_start(struct netmap_generic_adapter * na)168fb578518SFranco Fichtner void netmap_mitigation_start(struct netmap_generic_adapter *na)
169fb578518SFranco Fichtner {
170fb578518SFranco Fichtner 	ND("called");
171fb578518SFranco Fichtner }
172fb578518SFranco Fichtner 
netmap_mitigation_restart(struct netmap_generic_adapter * na)173fb578518SFranco Fichtner void netmap_mitigation_restart(struct netmap_generic_adapter *na)
174fb578518SFranco Fichtner {
175fb578518SFranco Fichtner 	ND("called");
176fb578518SFranco Fichtner }
177fb578518SFranco Fichtner 
netmap_mitigation_active(struct netmap_generic_adapter * na)178fb578518SFranco Fichtner int netmap_mitigation_active(struct netmap_generic_adapter *na)
179fb578518SFranco Fichtner {
180fb578518SFranco Fichtner 	ND("called");
181fb578518SFranco Fichtner 	return 0;
182fb578518SFranco Fichtner }
183fb578518SFranco Fichtner 
netmap_mitigation_cleanup(struct netmap_generic_adapter * na)184fb578518SFranco Fichtner void netmap_mitigation_cleanup(struct netmap_generic_adapter *na)
185fb578518SFranco Fichtner {
186fb578518SFranco Fichtner 	ND("called");
187fb578518SFranco Fichtner }
188fb578518SFranco Fichtner 
189fb578518SFranco Fichtner 
190fb578518SFranco Fichtner /*
191fb578518SFranco Fichtner  * In order to track whether pages are still mapped, we hook into
192fb578518SFranco Fichtner  * the standard cdev_pager and intercept the constructor and
193fb578518SFranco Fichtner  * destructor.
194fb578518SFranco Fichtner  */
195fb578518SFranco Fichtner 
196fb578518SFranco Fichtner struct netmap_vm_handle_t {
197fb578518SFranco Fichtner 	struct cdev 		*dev;
198fb578518SFranco Fichtner 	struct netmap_priv_d	*priv;
199fb578518SFranco Fichtner };
200fb578518SFranco Fichtner 
201fb578518SFranco Fichtner static int
netmap_dev_pager_ctor(void * handle,vm_ooffset_t size,vm_prot_t prot,vm_ooffset_t foff,struct ucred * cred,u_short * color)202fb578518SFranco Fichtner netmap_dev_pager_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot,
203fb578518SFranco Fichtner     vm_ooffset_t foff, struct ucred *cred, u_short *color)
204fb578518SFranco Fichtner {
205fb578518SFranco Fichtner 	struct netmap_vm_handle_t *vmh = handle;
206bf9f7c16SFranco Fichtner 	(void)vmh;
207fb578518SFranco Fichtner 	D("handle %p size %jd prot %d foff %jd",
208fb578518SFranco Fichtner 		handle, (intmax_t)size, prot, (intmax_t)foff);
209bf9f7c16SFranco Fichtner #if 0
210fb578518SFranco Fichtner 	dev_ref(vmh->dev);
211bf9f7c16SFranco Fichtner #endif
212fb578518SFranco Fichtner 	return 0;
213fb578518SFranco Fichtner }
214fb578518SFranco Fichtner 
215fb578518SFranco Fichtner 
216fb578518SFranco Fichtner static void
netmap_dev_pager_dtor(void * handle)217fb578518SFranco Fichtner netmap_dev_pager_dtor(void *handle)
218fb578518SFranco Fichtner {
219fb578518SFranco Fichtner 	struct netmap_vm_handle_t *vmh = handle;
220fb578518SFranco Fichtner 	struct cdev *dev = vmh->dev;
221fb578518SFranco Fichtner 	struct netmap_priv_d *priv = vmh->priv;
222bf9f7c16SFranco Fichtner 	(void)dev;
223fb578518SFranco Fichtner 	D("handle %p", handle);
224fb578518SFranco Fichtner 	netmap_dtor(priv);
225ed9bd855SFranco Fichtner 	kfree(vmh, M_DEVBUF);
226bf9f7c16SFranco Fichtner #if 0
227fb578518SFranco Fichtner 	dev_rel(dev);
228bf9f7c16SFranco Fichtner #endif
229fb578518SFranco Fichtner }
230fb578518SFranco Fichtner 
2313c0add62SFranco Fichtner MALLOC_DEFINE(M_FICT_PAGES, "", "");
2323c0add62SFranco Fichtner 
2333c0add62SFranco Fichtner static inline vm_page_t
vm_page_getfake(vm_paddr_t paddr,vm_memattr_t memattr)2343c0add62SFranco Fichtner vm_page_getfake(vm_paddr_t paddr, vm_memattr_t memattr)
2353c0add62SFranco Fichtner {
2363c0add62SFranco Fichtner 	vm_page_t m;
2373c0add62SFranco Fichtner 
238530e94fcSMatthew Dillon 	m = kmalloc(sizeof(struct vm_page), M_FICT_PAGES, M_WAITOK | M_ZERO);
2393c0add62SFranco Fichtner 	vm_page_initfake(m, paddr, memattr);
2403c0add62SFranco Fichtner 	return (m);
2413c0add62SFranco Fichtner }
2423c0add62SFranco Fichtner 
2433c0add62SFranco Fichtner static inline void
vm_page_updatefake(vm_page_t m,vm_paddr_t paddr,vm_memattr_t memattr)2443c0add62SFranco Fichtner vm_page_updatefake(vm_page_t m, vm_paddr_t paddr, vm_memattr_t memattr)
2453c0add62SFranco Fichtner {
2463c0add62SFranco Fichtner 	KASSERT((m->flags & PG_FICTITIOUS) != 0,
2473c0add62SFranco Fichtner 	    ("vm_page_updatefake: bad page %p", m));
2483c0add62SFranco Fichtner 	m->phys_addr = paddr;
2493c0add62SFranco Fichtner 	pmap_page_set_memattr(m, memattr);
2503c0add62SFranco Fichtner }
2513c0add62SFranco Fichtner 
252fb578518SFranco Fichtner static int
netmap_dev_pager_fault(vm_object_t object,vm_ooffset_t offset,int prot,vm_page_t * mres)253fb578518SFranco Fichtner netmap_dev_pager_fault(vm_object_t object, vm_ooffset_t offset,
254fb578518SFranco Fichtner 	int prot, vm_page_t *mres)
255fb578518SFranco Fichtner {
256fb578518SFranco Fichtner 	struct netmap_vm_handle_t *vmh = object->handle;
257fb578518SFranco Fichtner 	struct netmap_priv_d *priv = vmh->priv;
258fb578518SFranco Fichtner 	vm_paddr_t paddr;
259fb578518SFranco Fichtner 	vm_page_t page;
260fb578518SFranco Fichtner 	vm_memattr_t memattr;
261fb578518SFranco Fichtner 	vm_pindex_t pidx;
262fb578518SFranco Fichtner 
263fb578518SFranco Fichtner 	ND("object %p offset %jd prot %d mres %p",
264fb578518SFranco Fichtner 			object, (intmax_t)offset, prot, mres);
265fb578518SFranco Fichtner 	memattr = object->memattr;
266fb578518SFranco Fichtner 	pidx = OFF_TO_IDX(offset);
267fb578518SFranco Fichtner 	paddr = netmap_mem_ofstophys(priv->np_mref, offset);
268fb578518SFranco Fichtner 	if (paddr == 0)
269fb578518SFranco Fichtner 		return VM_PAGER_FAIL;
270fb578518SFranco Fichtner 
271fb578518SFranco Fichtner 	if (((*mres)->flags & PG_FICTITIOUS) != 0) {
272fb578518SFranco Fichtner 		/*
273fb578518SFranco Fichtner 		 * If the passed in result page is a fake page, update it with
274fb578518SFranco Fichtner 		 * the new physical address.
275fb578518SFranco Fichtner 		 */
276fb578518SFranco Fichtner 		page = *mres;
277fb578518SFranco Fichtner 		vm_page_updatefake(page, paddr, memattr);
278fb578518SFranco Fichtner 	} else {
279fb578518SFranco Fichtner 		/*
280fb578518SFranco Fichtner 		 * Replace the passed in reqpage page with our own fake page and
281fb578518SFranco Fichtner 		 * free up the all of the original pages.
282fb578518SFranco Fichtner 		 */
283fb578518SFranco Fichtner #ifndef VM_OBJECT_WUNLOCK	/* FreeBSD < 10.x */
284fb578518SFranco Fichtner #define VM_OBJECT_WUNLOCK VM_OBJECT_UNLOCK
285fb578518SFranco Fichtner #define VM_OBJECT_WLOCK	VM_OBJECT_LOCK
286fb578518SFranco Fichtner #endif /* VM_OBJECT_WUNLOCK */
287fb578518SFranco Fichtner 
288fb578518SFranco Fichtner 		VM_OBJECT_WUNLOCK(object);
289fb578518SFranco Fichtner 		page = vm_page_getfake(paddr, memattr);
290fb578518SFranco Fichtner 		VM_OBJECT_WLOCK(object);
291fb578518SFranco Fichtner 		vm_page_free(*mres);
292fb578518SFranco Fichtner 		*mres = page;
293fb578518SFranco Fichtner 		vm_page_insert(page, object, pidx);
294fb578518SFranco Fichtner 	}
295fb578518SFranco Fichtner 	page->valid = VM_PAGE_BITS_ALL;
296fb578518SFranco Fichtner 	return (VM_PAGER_OK);
297fb578518SFranco Fichtner }
298fb578518SFranco Fichtner 
299fb578518SFranco Fichtner 
300fb578518SFranco Fichtner static struct cdev_pager_ops netmap_cdev_pager_ops = {
301fb578518SFranco Fichtner 	.cdev_pg_ctor = netmap_dev_pager_ctor,
302fb578518SFranco Fichtner 	.cdev_pg_dtor = netmap_dev_pager_dtor,
303fb578518SFranco Fichtner 	.cdev_pg_fault = netmap_dev_pager_fault,
304fb578518SFranco Fichtner };
305fb578518SFranco Fichtner 
306fb578518SFranco Fichtner 
307fb578518SFranco Fichtner static int
netmap_mmap_single(struct dev_mmap_single_args * ap)30813431b3eSFranco Fichtner netmap_mmap_single(struct dev_mmap_single_args *ap)
309fb578518SFranco Fichtner {
310fb578518SFranco Fichtner 	int error;
31113431b3eSFranco Fichtner 	struct cdev *cdev = ap->a_head.a_dev;
31213431b3eSFranco Fichtner 	vm_ooffset_t *foff = ap->a_offset;
31313431b3eSFranco Fichtner 	vm_object_t *objp = ap->a_object;
31413431b3eSFranco Fichtner 	vm_size_t objsize = ap->a_size;
315fb578518SFranco Fichtner 	struct netmap_vm_handle_t *vmh;
316fb578518SFranco Fichtner 	struct netmap_priv_d *priv;
31713431b3eSFranco Fichtner 	int prot = ap->a_nprot;
318fb578518SFranco Fichtner 	vm_object_t obj;
319fb578518SFranco Fichtner 
320fb578518SFranco Fichtner 	D("cdev %p foff %jd size %jd objp %p prot %d", cdev,
321fb578518SFranco Fichtner 	    (intmax_t )*foff, (intmax_t )objsize, objp, prot);
322fb578518SFranco Fichtner 
323ed9bd855SFranco Fichtner 	vmh = kmalloc(sizeof(struct netmap_vm_handle_t), M_DEVBUF,
324fb578518SFranco Fichtner 			      M_NOWAIT | M_ZERO);
325fb578518SFranco Fichtner 	if (vmh == NULL)
326fb578518SFranco Fichtner 		return ENOMEM;
327fb578518SFranco Fichtner 	vmh->dev = cdev;
328fb578518SFranco Fichtner 
329fb578518SFranco Fichtner 	NMG_LOCK();
3308b6c789bSFranco Fichtner 	error = devfs_get_cdevpriv(ap->a_fp, (void**)&priv);
3318b6c789bSFranco Fichtner 	if (error)
3328b6c789bSFranco Fichtner 		goto err_unlock;
333fb578518SFranco Fichtner 	vmh->priv = priv;
334fb578518SFranco Fichtner 	priv->np_refcount++;
335fb578518SFranco Fichtner 	NMG_UNLOCK();
336fb578518SFranco Fichtner 
337fb578518SFranco Fichtner 	error = netmap_get_memory(priv);
338fb578518SFranco Fichtner 	if (error)
339fb578518SFranco Fichtner 		goto err_deref;
340fb578518SFranco Fichtner 
341fb578518SFranco Fichtner 	obj = cdev_pager_allocate(vmh, OBJT_DEVICE,
342fb578518SFranco Fichtner 		&netmap_cdev_pager_ops, objsize, prot,
343fb578518SFranco Fichtner 		*foff, NULL);
344fb578518SFranco Fichtner 	if (obj == NULL) {
345fb578518SFranco Fichtner 		D("cdev_pager_allocate failed");
346fb578518SFranco Fichtner 		error = EINVAL;
347fb578518SFranco Fichtner 		goto err_deref;
348fb578518SFranco Fichtner 	}
349fb578518SFranco Fichtner 
350fb578518SFranco Fichtner 	*objp = obj;
351fb578518SFranco Fichtner 	return 0;
352fb578518SFranco Fichtner 
353fb578518SFranco Fichtner err_deref:
354fb578518SFranco Fichtner 	NMG_LOCK();
355fb578518SFranco Fichtner 	priv->np_refcount--;
3568b6c789bSFranco Fichtner err_unlock:
357fb578518SFranco Fichtner 	NMG_UNLOCK();
358fb578518SFranco Fichtner // err:
359ed9bd855SFranco Fichtner 	kfree(vmh, M_DEVBUF);
360fb578518SFranco Fichtner 	return error;
361fb578518SFranco Fichtner }
362fb578518SFranco Fichtner 
363fb578518SFranco Fichtner 
3648b6c789bSFranco Fichtner // XXX can we remove this ?
365fb578518SFranco Fichtner static int
netmap_close(struct dev_close_args * ap)36613431b3eSFranco Fichtner netmap_close(struct dev_close_args *ap)
367fb578518SFranco Fichtner {
368fb578518SFranco Fichtner 	if (netmap_verbose)
36913431b3eSFranco Fichtner 		D("dev %p fflag 0x%x devtype %d",
37013431b3eSFranco Fichtner 			ap->a_head.a_dev, ap->a_fflag, ap->a_devtype);
371fb578518SFranco Fichtner 	return 0;
372fb578518SFranco Fichtner }
373fb578518SFranco Fichtner 
374fb578518SFranco Fichtner 
375fb578518SFranco Fichtner static int
netmap_open(struct dev_open_args * ap)37613431b3eSFranco Fichtner netmap_open(struct dev_open_args *ap)
377fb578518SFranco Fichtner {
378fb578518SFranco Fichtner 	struct netmap_priv_d *priv;
3798b6c789bSFranco Fichtner 	int error;
380fb578518SFranco Fichtner 
381fb578518SFranco Fichtner 	// XXX wait or nowait ?
382ed9bd855SFranco Fichtner 	priv = kmalloc(sizeof(struct netmap_priv_d), M_DEVBUF,
383fb578518SFranco Fichtner 			      M_NOWAIT | M_ZERO);
384fb578518SFranco Fichtner 	if (priv == NULL)
385fb578518SFranco Fichtner 		return ENOMEM;
386fb578518SFranco Fichtner 
3878b6c789bSFranco Fichtner 	error = devfs_set_cdevpriv(ap->a_fp, priv, netmap_dtor);
3888b6c789bSFranco Fichtner 	if (error)
3898b6c789bSFranco Fichtner 	        return error;
390fb578518SFranco Fichtner 
391fb578518SFranco Fichtner 	priv->np_refcount = 1;
392fb578518SFranco Fichtner 
393fb578518SFranco Fichtner 	return 0;
394fb578518SFranco Fichtner }
395fb578518SFranco Fichtner 
396fb578518SFranco Fichtner 
397bf9f7c16SFranco Fichtner struct dev_ops netmap_cdevsw = {
39813431b3eSFranco Fichtner 	{ "netmap", 0, 0 },
399fb578518SFranco Fichtner 	.d_open = netmap_open,
400fb578518SFranco Fichtner 	.d_mmap_single = netmap_mmap_single,
401fb578518SFranco Fichtner 	.d_ioctl = netmap_ioctl,
402f27ed164SFranco Fichtner 	.d_kqfilter = netmap_kqfilter,
40313431b3eSFranco Fichtner 	.d_close = netmap_close,
404fb578518SFranco Fichtner };
405fb578518SFranco Fichtner 
406fb578518SFranco Fichtner 
407fb578518SFranco Fichtner /*
408fb578518SFranco Fichtner  * Kernel entry point.
409fb578518SFranco Fichtner  *
410fb578518SFranco Fichtner  * Initialize/finalize the module and return.
411fb578518SFranco Fichtner  *
412fb578518SFranco Fichtner  * Return 0 on success, errno on failure.
413fb578518SFranco Fichtner  */
414fb578518SFranco Fichtner static int
netmap_loader(__unused struct module * module,int event,__unused void * arg)415fb578518SFranco Fichtner netmap_loader(__unused struct module *module, int event, __unused void *arg)
416fb578518SFranco Fichtner {
417fb578518SFranco Fichtner 	int error = 0;
418fb578518SFranco Fichtner 
419fb578518SFranco Fichtner 	switch (event) {
420fb578518SFranco Fichtner 	case MOD_LOAD:
421fb578518SFranco Fichtner 		error = netmap_init();
422fb578518SFranco Fichtner 		break;
423fb578518SFranco Fichtner 
424fb578518SFranco Fichtner 	case MOD_UNLOAD:
425fb578518SFranco Fichtner 		netmap_fini();
426fb578518SFranco Fichtner 		break;
427fb578518SFranco Fichtner 
428fb578518SFranco Fichtner 	default:
429fb578518SFranco Fichtner 		error = EOPNOTSUPP;
430fb578518SFranco Fichtner 		break;
431fb578518SFranco Fichtner 	}
432fb578518SFranco Fichtner 
433fb578518SFranco Fichtner 	return (error);
434fb578518SFranco Fichtner }
435fb578518SFranco Fichtner 
436fb578518SFranco Fichtner 
437fb578518SFranco Fichtner DEV_MODULE(netmap, netmap_loader, NULL);
438