1f9790aebSLuigi Rizzo /*
217885a7bSLuigi Rizzo  * Copyright (C) 2013-2014 Universita` di Pisa. All rights reserved.
3f9790aebSLuigi Rizzo  *
4f9790aebSLuigi Rizzo  * Redistribution and use in source and binary forms, with or without
5f9790aebSLuigi Rizzo  * modification, are permitted provided that the following conditions
6f9790aebSLuigi Rizzo  * are met:
7f9790aebSLuigi Rizzo  *   1. Redistributions of source code must retain the above copyright
8f9790aebSLuigi Rizzo  *      notice, this list of conditions and the following disclaimer.
9f9790aebSLuigi Rizzo  *   2. Redistributions in binary form must reproduce the above copyright
10f9790aebSLuigi Rizzo  *      notice, this list of conditions and the following disclaimer in the
11f9790aebSLuigi Rizzo  *      documentation and/or other materials provided with the distribution.
12f9790aebSLuigi Rizzo  *
13f9790aebSLuigi Rizzo  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14f9790aebSLuigi Rizzo  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15f9790aebSLuigi Rizzo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16f9790aebSLuigi Rizzo  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17f9790aebSLuigi Rizzo  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18f9790aebSLuigi Rizzo  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19f9790aebSLuigi Rizzo  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20f9790aebSLuigi Rizzo  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21f9790aebSLuigi Rizzo  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22f9790aebSLuigi Rizzo  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23f9790aebSLuigi Rizzo  * SUCH DAMAGE.
24f9790aebSLuigi Rizzo  */
25f9790aebSLuigi Rizzo 
26f9790aebSLuigi Rizzo /* $FreeBSD$ */
27f9790aebSLuigi Rizzo 
28f9790aebSLuigi Rizzo #include <sys/types.h>
29f9790aebSLuigi Rizzo #include <sys/module.h>
30f9790aebSLuigi Rizzo #include <sys/errno.h>
31f9790aebSLuigi Rizzo #include <sys/param.h>  /* defines used in kernel.h */
32*f0ea3689SLuigi Rizzo #include <sys/poll.h>  /* POLLIN, POLLOUT */
33f9790aebSLuigi Rizzo #include <sys/kernel.h> /* types used in module initialization */
34f9790aebSLuigi Rizzo #include <sys/conf.h>	/* DEV_MODULE */
35*f0ea3689SLuigi Rizzo #include <sys/endian.h>
36f9790aebSLuigi Rizzo 
37f9790aebSLuigi Rizzo #include <sys/rwlock.h>
38f9790aebSLuigi Rizzo 
39f9790aebSLuigi Rizzo #include <vm/vm.h>      /* vtophys */
40f9790aebSLuigi Rizzo #include <vm/pmap.h>    /* vtophys */
41f9790aebSLuigi Rizzo #include <vm/vm_param.h>
42f9790aebSLuigi Rizzo #include <vm/vm_object.h>
43f9790aebSLuigi Rizzo #include <vm/vm_page.h>
44f9790aebSLuigi Rizzo #include <vm/vm_pager.h>
45f9790aebSLuigi Rizzo #include <vm/uma.h>
46f9790aebSLuigi Rizzo 
47f9790aebSLuigi Rizzo 
48f9790aebSLuigi Rizzo #include <sys/malloc.h>
49f9790aebSLuigi Rizzo #include <sys/socket.h> /* sockaddrs */
50f9790aebSLuigi Rizzo #include <sys/selinfo.h>
51f9790aebSLuigi Rizzo #include <net/if.h>
52f9790aebSLuigi Rizzo #include <net/if_var.h>
53f9790aebSLuigi Rizzo #include <machine/bus.h>        /* bus_dmamap_* */
54*f0ea3689SLuigi Rizzo #include <netinet/in.h>		/* in6_cksum_pseudo() */
55*f0ea3689SLuigi Rizzo #include <machine/in_cksum.h>  /* in_pseudo(), in_cksum_hdr() */
56f9790aebSLuigi Rizzo 
57f9790aebSLuigi Rizzo #include <net/netmap.h>
58f9790aebSLuigi Rizzo #include <dev/netmap/netmap_kern.h>
59f9790aebSLuigi Rizzo #include <dev/netmap/netmap_mem2.h>
60f9790aebSLuigi Rizzo 
61f9790aebSLuigi Rizzo 
62f9790aebSLuigi Rizzo /* ======================== FREEBSD-SPECIFIC ROUTINES ================== */
63f9790aebSLuigi Rizzo 
64*f0ea3689SLuigi Rizzo rawsum_t nm_csum_raw(uint8_t *data, size_t len, rawsum_t cur_sum)
65*f0ea3689SLuigi Rizzo {
66*f0ea3689SLuigi Rizzo 	/* TODO XXX please use the FreeBSD implementation for this. */
67*f0ea3689SLuigi Rizzo 	uint16_t *words = (uint16_t *)data;
68*f0ea3689SLuigi Rizzo 	int nw = len / 2;
69*f0ea3689SLuigi Rizzo 	int i;
70*f0ea3689SLuigi Rizzo 
71*f0ea3689SLuigi Rizzo 	for (i = 0; i < nw; i++)
72*f0ea3689SLuigi Rizzo 		cur_sum += be16toh(words[i]);
73*f0ea3689SLuigi Rizzo 
74*f0ea3689SLuigi Rizzo 	if (len & 1)
75*f0ea3689SLuigi Rizzo 		cur_sum += (data[len-1] << 8);
76*f0ea3689SLuigi Rizzo 
77*f0ea3689SLuigi Rizzo 	return cur_sum;
78*f0ea3689SLuigi Rizzo }
79*f0ea3689SLuigi Rizzo 
80*f0ea3689SLuigi Rizzo /* Fold a raw checksum: 'cur_sum' is in host byte order, while the
81*f0ea3689SLuigi Rizzo  * return value is in network byte order.
82*f0ea3689SLuigi Rizzo  */
83*f0ea3689SLuigi Rizzo uint16_t nm_csum_fold(rawsum_t cur_sum)
84*f0ea3689SLuigi Rizzo {
85*f0ea3689SLuigi Rizzo 	/* TODO XXX please use the FreeBSD implementation for this. */
86*f0ea3689SLuigi Rizzo 	while (cur_sum >> 16)
87*f0ea3689SLuigi Rizzo 		cur_sum = (cur_sum & 0xFFFF) + (cur_sum >> 16);
88*f0ea3689SLuigi Rizzo 
89*f0ea3689SLuigi Rizzo 	return htobe16((~cur_sum) & 0xFFFF);
90*f0ea3689SLuigi Rizzo }
91*f0ea3689SLuigi Rizzo 
92*f0ea3689SLuigi Rizzo uint16_t nm_csum_ipv4(struct nm_iphdr *iph)
93*f0ea3689SLuigi Rizzo {
94*f0ea3689SLuigi Rizzo #if 0
95*f0ea3689SLuigi Rizzo 	return in_cksum_hdr((void *)iph);
96*f0ea3689SLuigi Rizzo #else
97*f0ea3689SLuigi Rizzo 	return nm_csum_fold(nm_csum_raw((uint8_t*)iph, sizeof(struct nm_iphdr), 0));
98*f0ea3689SLuigi Rizzo #endif
99*f0ea3689SLuigi Rizzo }
100*f0ea3689SLuigi Rizzo 
101*f0ea3689SLuigi Rizzo void nm_csum_tcpudp_ipv4(struct nm_iphdr *iph, void *data,
102*f0ea3689SLuigi Rizzo 					size_t datalen, uint16_t *check)
103*f0ea3689SLuigi Rizzo {
104*f0ea3689SLuigi Rizzo 	uint16_t pseudolen = datalen + iph->protocol;
105*f0ea3689SLuigi Rizzo 
106*f0ea3689SLuigi Rizzo 	/* Compute and insert the pseudo-header cheksum. */
107*f0ea3689SLuigi Rizzo 	*check = in_pseudo(iph->saddr, iph->daddr,
108*f0ea3689SLuigi Rizzo 				 htobe16(pseudolen));
109*f0ea3689SLuigi Rizzo 	/* Compute the checksum on TCP/UDP header + payload
110*f0ea3689SLuigi Rizzo 	 * (includes the pseudo-header).
111*f0ea3689SLuigi Rizzo 	 */
112*f0ea3689SLuigi Rizzo 	*check = nm_csum_fold(nm_csum_raw(data, datalen, 0));
113*f0ea3689SLuigi Rizzo }
114*f0ea3689SLuigi Rizzo 
115*f0ea3689SLuigi Rizzo void nm_csum_tcpudp_ipv6(struct nm_ipv6hdr *ip6h, void *data,
116*f0ea3689SLuigi Rizzo 					size_t datalen, uint16_t *check)
117*f0ea3689SLuigi Rizzo {
118*f0ea3689SLuigi Rizzo #ifdef INET6
119*f0ea3689SLuigi Rizzo 	*check = in6_cksum_pseudo((void*)ip6h, datalen, ip6h->nexthdr, 0);
120*f0ea3689SLuigi Rizzo 	*check = nm_csum_fold(nm_csum_raw(data, datalen, 0));
121*f0ea3689SLuigi Rizzo #else
122*f0ea3689SLuigi Rizzo 	static int notsupported = 0;
123*f0ea3689SLuigi Rizzo 	if (!notsupported) {
124*f0ea3689SLuigi Rizzo 		notsupported = 1;
125*f0ea3689SLuigi Rizzo 		D("inet6 segmentation not supported");
126*f0ea3689SLuigi Rizzo 	}
127*f0ea3689SLuigi Rizzo #endif
128*f0ea3689SLuigi Rizzo }
129*f0ea3689SLuigi Rizzo 
130*f0ea3689SLuigi Rizzo 
131f9790aebSLuigi Rizzo /*
132f9790aebSLuigi Rizzo  * Intercept the rx routine in the standard device driver.
133f9790aebSLuigi Rizzo  * Second argument is non-zero to intercept, 0 to restore
134f9790aebSLuigi Rizzo  */
135f9790aebSLuigi Rizzo int
136f9790aebSLuigi Rizzo netmap_catch_rx(struct netmap_adapter *na, int intercept)
137f9790aebSLuigi Rizzo {
138f9790aebSLuigi Rizzo 	struct netmap_generic_adapter *gna = (struct netmap_generic_adapter *)na;
139f9790aebSLuigi Rizzo 	struct ifnet *ifp = na->ifp;
140f9790aebSLuigi Rizzo 
141f9790aebSLuigi Rizzo 	if (intercept) {
142f9790aebSLuigi Rizzo 		if (gna->save_if_input) {
143f9790aebSLuigi Rizzo 			D("cannot intercept again");
144f9790aebSLuigi Rizzo 			return EINVAL; /* already set */
145f9790aebSLuigi Rizzo 		}
146f9790aebSLuigi Rizzo 		gna->save_if_input = ifp->if_input;
147f9790aebSLuigi Rizzo 		ifp->if_input = generic_rx_handler;
148f9790aebSLuigi Rizzo 	} else {
149f9790aebSLuigi Rizzo 		if (!gna->save_if_input){
150f9790aebSLuigi Rizzo 			D("cannot restore");
151f9790aebSLuigi Rizzo 			return EINVAL;  /* not saved */
152f9790aebSLuigi Rizzo 		}
153f9790aebSLuigi Rizzo 		ifp->if_input = gna->save_if_input;
154f9790aebSLuigi Rizzo 		gna->save_if_input = NULL;
155f9790aebSLuigi Rizzo 	}
156f9790aebSLuigi Rizzo 
157f9790aebSLuigi Rizzo 	return 0;
158f9790aebSLuigi Rizzo }
159f9790aebSLuigi Rizzo 
16017885a7bSLuigi Rizzo 
161f9790aebSLuigi Rizzo /*
162f9790aebSLuigi Rizzo  * Intercept the packet steering routine in the tx path,
163f9790aebSLuigi Rizzo  * so that we can decide which queue is used for an mbuf.
164f9790aebSLuigi Rizzo  * Second argument is non-zero to intercept, 0 to restore.
165*f0ea3689SLuigi Rizzo  * On freebsd we just intercept if_transmit.
166f9790aebSLuigi Rizzo  */
167f9790aebSLuigi Rizzo void
16817885a7bSLuigi Rizzo netmap_catch_tx(struct netmap_generic_adapter *gna, int enable)
169f9790aebSLuigi Rizzo {
17017885a7bSLuigi Rizzo 	struct netmap_adapter *na = &gna->up.up;
17117885a7bSLuigi Rizzo 	struct ifnet *ifp = na->ifp;
17217885a7bSLuigi Rizzo 
173f9790aebSLuigi Rizzo 	if (enable) {
17417885a7bSLuigi Rizzo 		na->if_transmit = ifp->if_transmit;
17517885a7bSLuigi Rizzo 		ifp->if_transmit = netmap_transmit;
176f9790aebSLuigi Rizzo 	} else {
17717885a7bSLuigi Rizzo 		ifp->if_transmit = na->if_transmit;
178f9790aebSLuigi Rizzo 	}
179f9790aebSLuigi Rizzo }
180f9790aebSLuigi Rizzo 
18117885a7bSLuigi Rizzo 
182*f0ea3689SLuigi Rizzo /*
183*f0ea3689SLuigi Rizzo  * Transmit routine used by generic_netmap_txsync(). Returns 0 on success
184f9790aebSLuigi Rizzo  * and non-zero on error (which may be packet drops or other errors).
185f9790aebSLuigi Rizzo  * addr and len identify the netmap buffer, m is the (preallocated)
186f9790aebSLuigi Rizzo  * mbuf to use for transmissions.
187f9790aebSLuigi Rizzo  *
188f9790aebSLuigi Rizzo  * We should add a reference to the mbuf so the m_freem() at the end
189f9790aebSLuigi Rizzo  * of the transmission does not consume resources.
190f9790aebSLuigi Rizzo  *
191f9790aebSLuigi Rizzo  * On FreeBSD, and on multiqueue cards, we can force the queue using
192f9790aebSLuigi Rizzo  *      if ((m->m_flags & M_FLOWID) != 0)
193f9790aebSLuigi Rizzo  *              i = m->m_pkthdr.flowid % adapter->num_queues;
194f9790aebSLuigi Rizzo  *      else
195f9790aebSLuigi Rizzo  *              i = curcpu % adapter->num_queues;
196f9790aebSLuigi Rizzo  *
197f9790aebSLuigi Rizzo  */
198f9790aebSLuigi Rizzo int
199f9790aebSLuigi Rizzo generic_xmit_frame(struct ifnet *ifp, struct mbuf *m,
200f9790aebSLuigi Rizzo 	void *addr, u_int len, u_int ring_nr)
201f9790aebSLuigi Rizzo {
202f9790aebSLuigi Rizzo 	int ret;
203f9790aebSLuigi Rizzo 
204f9790aebSLuigi Rizzo 	m->m_len = m->m_pkthdr.len = 0;
205f9790aebSLuigi Rizzo 
206f9790aebSLuigi Rizzo 	// copy data to the mbuf
207f9790aebSLuigi Rizzo 	m_copyback(m, 0, len, addr);
208f9790aebSLuigi Rizzo 	// inc refcount. We are alone, so we can skip the atomic
209f9790aebSLuigi Rizzo 	atomic_fetchadd_int(m->m_ext.ref_cnt, 1);
210f9790aebSLuigi Rizzo 	m->m_flags |= M_FLOWID;
211f9790aebSLuigi Rizzo 	m->m_pkthdr.flowid = ring_nr;
212f9790aebSLuigi Rizzo 	m->m_pkthdr.rcvif = ifp; /* used for tx notification */
21317885a7bSLuigi Rizzo 	ret = NA(ifp)->if_transmit(ifp, m);
214f9790aebSLuigi Rizzo 	return ret;
215f9790aebSLuigi Rizzo }
216f9790aebSLuigi Rizzo 
21717885a7bSLuigi Rizzo 
218f9790aebSLuigi Rizzo /*
219f9790aebSLuigi Rizzo  * The following two functions are empty until we have a generic
220f9790aebSLuigi Rizzo  * way to extract the info from the ifp
221f9790aebSLuigi Rizzo  */
222f9790aebSLuigi Rizzo int
223f9790aebSLuigi Rizzo generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *rx)
224f9790aebSLuigi Rizzo {
225f9790aebSLuigi Rizzo 	D("called");
226f9790aebSLuigi Rizzo 	return 0;
227f9790aebSLuigi Rizzo }
228f9790aebSLuigi Rizzo 
22917885a7bSLuigi Rizzo 
230f9790aebSLuigi Rizzo void
231f9790aebSLuigi Rizzo generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq)
232f9790aebSLuigi Rizzo {
233f9790aebSLuigi Rizzo 	D("called");
234*f0ea3689SLuigi Rizzo 	*txq = netmap_generic_rings;
235*f0ea3689SLuigi Rizzo 	*rxq = netmap_generic_rings;
236f9790aebSLuigi Rizzo }
237f9790aebSLuigi Rizzo 
23817885a7bSLuigi Rizzo 
239*f0ea3689SLuigi Rizzo void netmap_mitigation_init(struct nm_generic_mit *mit, struct netmap_adapter *na)
240f9790aebSLuigi Rizzo {
241f9790aebSLuigi Rizzo 	ND("called");
242*f0ea3689SLuigi Rizzo 	mit->mit_pending = 0;
243*f0ea3689SLuigi Rizzo 	mit->mit_na = na;
244f9790aebSLuigi Rizzo }
245f9790aebSLuigi Rizzo 
246f9790aebSLuigi Rizzo 
247*f0ea3689SLuigi Rizzo void netmap_mitigation_start(struct nm_generic_mit *mit)
248f9790aebSLuigi Rizzo {
249f9790aebSLuigi Rizzo 	ND("called");
250f9790aebSLuigi Rizzo }
251f9790aebSLuigi Rizzo 
25217885a7bSLuigi Rizzo 
253*f0ea3689SLuigi Rizzo void netmap_mitigation_restart(struct nm_generic_mit *mit)
254f9790aebSLuigi Rizzo {
255f9790aebSLuigi Rizzo 	ND("called");
256f9790aebSLuigi Rizzo }
257f9790aebSLuigi Rizzo 
25817885a7bSLuigi Rizzo 
259*f0ea3689SLuigi Rizzo int netmap_mitigation_active(struct nm_generic_mit *mit)
260f9790aebSLuigi Rizzo {
261f9790aebSLuigi Rizzo 	ND("called");
262f9790aebSLuigi Rizzo 	return 0;
263f9790aebSLuigi Rizzo }
264f9790aebSLuigi Rizzo 
26517885a7bSLuigi Rizzo 
266*f0ea3689SLuigi Rizzo void netmap_mitigation_cleanup(struct nm_generic_mit *mit)
267f9790aebSLuigi Rizzo {
268f9790aebSLuigi Rizzo 	ND("called");
269f9790aebSLuigi Rizzo }
270f9790aebSLuigi Rizzo 
27117885a7bSLuigi Rizzo 
272f9790aebSLuigi Rizzo /*
273f9790aebSLuigi Rizzo  * In order to track whether pages are still mapped, we hook into
274f9790aebSLuigi Rizzo  * the standard cdev_pager and intercept the constructor and
275f9790aebSLuigi Rizzo  * destructor.
276f9790aebSLuigi Rizzo  */
277f9790aebSLuigi Rizzo 
278f9790aebSLuigi Rizzo struct netmap_vm_handle_t {
279f9790aebSLuigi Rizzo 	struct cdev 		*dev;
280f9790aebSLuigi Rizzo 	struct netmap_priv_d	*priv;
281f9790aebSLuigi Rizzo };
282f9790aebSLuigi Rizzo 
28317885a7bSLuigi Rizzo 
284f9790aebSLuigi Rizzo static int
285f9790aebSLuigi Rizzo netmap_dev_pager_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot,
286f9790aebSLuigi Rizzo     vm_ooffset_t foff, struct ucred *cred, u_short *color)
287f9790aebSLuigi Rizzo {
288f9790aebSLuigi Rizzo 	struct netmap_vm_handle_t *vmh = handle;
289*f0ea3689SLuigi Rizzo 
290*f0ea3689SLuigi Rizzo 	if (netmap_verbose)
291f9790aebSLuigi Rizzo 		D("handle %p size %jd prot %d foff %jd",
292f9790aebSLuigi Rizzo 			handle, (intmax_t)size, prot, (intmax_t)foff);
293f9790aebSLuigi Rizzo 	dev_ref(vmh->dev);
294f9790aebSLuigi Rizzo 	return 0;
295f9790aebSLuigi Rizzo }
296f9790aebSLuigi Rizzo 
297f9790aebSLuigi Rizzo 
298f9790aebSLuigi Rizzo static void
299f9790aebSLuigi Rizzo netmap_dev_pager_dtor(void *handle)
300f9790aebSLuigi Rizzo {
301f9790aebSLuigi Rizzo 	struct netmap_vm_handle_t *vmh = handle;
302f9790aebSLuigi Rizzo 	struct cdev *dev = vmh->dev;
303f9790aebSLuigi Rizzo 	struct netmap_priv_d *priv = vmh->priv;
304*f0ea3689SLuigi Rizzo 
305*f0ea3689SLuigi Rizzo 	if (netmap_verbose)
306f9790aebSLuigi Rizzo 		D("handle %p", handle);
307f9790aebSLuigi Rizzo 	netmap_dtor(priv);
308f9790aebSLuigi Rizzo 	free(vmh, M_DEVBUF);
309f9790aebSLuigi Rizzo 	dev_rel(dev);
310f9790aebSLuigi Rizzo }
311f9790aebSLuigi Rizzo 
31217885a7bSLuigi Rizzo 
313f9790aebSLuigi Rizzo static int
314f9790aebSLuigi Rizzo netmap_dev_pager_fault(vm_object_t object, vm_ooffset_t offset,
315f9790aebSLuigi Rizzo 	int prot, vm_page_t *mres)
316f9790aebSLuigi Rizzo {
317f9790aebSLuigi Rizzo 	struct netmap_vm_handle_t *vmh = object->handle;
318f9790aebSLuigi Rizzo 	struct netmap_priv_d *priv = vmh->priv;
319f9790aebSLuigi Rizzo 	vm_paddr_t paddr;
320f9790aebSLuigi Rizzo 	vm_page_t page;
321f9790aebSLuigi Rizzo 	vm_memattr_t memattr;
322f9790aebSLuigi Rizzo 	vm_pindex_t pidx;
323f9790aebSLuigi Rizzo 
324f9790aebSLuigi Rizzo 	ND("object %p offset %jd prot %d mres %p",
325f9790aebSLuigi Rizzo 			object, (intmax_t)offset, prot, mres);
326f9790aebSLuigi Rizzo 	memattr = object->memattr;
327f9790aebSLuigi Rizzo 	pidx = OFF_TO_IDX(offset);
328f9790aebSLuigi Rizzo 	paddr = netmap_mem_ofstophys(priv->np_mref, offset);
329f9790aebSLuigi Rizzo 	if (paddr == 0)
330f9790aebSLuigi Rizzo 		return VM_PAGER_FAIL;
331f9790aebSLuigi Rizzo 
332f9790aebSLuigi Rizzo 	if (((*mres)->flags & PG_FICTITIOUS) != 0) {
333f9790aebSLuigi Rizzo 		/*
334f9790aebSLuigi Rizzo 		 * If the passed in result page is a fake page, update it with
335f9790aebSLuigi Rizzo 		 * the new physical address.
336f9790aebSLuigi Rizzo 		 */
337f9790aebSLuigi Rizzo 		page = *mres;
338f9790aebSLuigi Rizzo 		vm_page_updatefake(page, paddr, memattr);
339f9790aebSLuigi Rizzo 	} else {
340f9790aebSLuigi Rizzo 		/*
341f9790aebSLuigi Rizzo 		 * Replace the passed in reqpage page with our own fake page and
342f9790aebSLuigi Rizzo 		 * free up the all of the original pages.
343f9790aebSLuigi Rizzo 		 */
344f9790aebSLuigi Rizzo #ifndef VM_OBJECT_WUNLOCK	/* FreeBSD < 10.x */
345f9790aebSLuigi Rizzo #define VM_OBJECT_WUNLOCK VM_OBJECT_UNLOCK
346f9790aebSLuigi Rizzo #define VM_OBJECT_WLOCK	VM_OBJECT_LOCK
347f9790aebSLuigi Rizzo #endif /* VM_OBJECT_WUNLOCK */
348f9790aebSLuigi Rizzo 
349f9790aebSLuigi Rizzo 		VM_OBJECT_WUNLOCK(object);
350f9790aebSLuigi Rizzo 		page = vm_page_getfake(paddr, memattr);
351f9790aebSLuigi Rizzo 		VM_OBJECT_WLOCK(object);
352f9790aebSLuigi Rizzo 		vm_page_lock(*mres);
353f9790aebSLuigi Rizzo 		vm_page_free(*mres);
354f9790aebSLuigi Rizzo 		vm_page_unlock(*mres);
355f9790aebSLuigi Rizzo 		*mres = page;
356f9790aebSLuigi Rizzo 		vm_page_insert(page, object, pidx);
357f9790aebSLuigi Rizzo 	}
358f9790aebSLuigi Rizzo 	page->valid = VM_PAGE_BITS_ALL;
359f9790aebSLuigi Rizzo 	return (VM_PAGER_OK);
360f9790aebSLuigi Rizzo }
361f9790aebSLuigi Rizzo 
362f9790aebSLuigi Rizzo 
363f9790aebSLuigi Rizzo static struct cdev_pager_ops netmap_cdev_pager_ops = {
364f9790aebSLuigi Rizzo 	.cdev_pg_ctor = netmap_dev_pager_ctor,
365f9790aebSLuigi Rizzo 	.cdev_pg_dtor = netmap_dev_pager_dtor,
366f9790aebSLuigi Rizzo 	.cdev_pg_fault = netmap_dev_pager_fault,
367f9790aebSLuigi Rizzo };
368f9790aebSLuigi Rizzo 
369f9790aebSLuigi Rizzo 
370f9790aebSLuigi Rizzo static int
371f9790aebSLuigi Rizzo netmap_mmap_single(struct cdev *cdev, vm_ooffset_t *foff,
372f9790aebSLuigi Rizzo 	vm_size_t objsize,  vm_object_t *objp, int prot)
373f9790aebSLuigi Rizzo {
374f9790aebSLuigi Rizzo 	int error;
375f9790aebSLuigi Rizzo 	struct netmap_vm_handle_t *vmh;
376f9790aebSLuigi Rizzo 	struct netmap_priv_d *priv;
377f9790aebSLuigi Rizzo 	vm_object_t obj;
378f9790aebSLuigi Rizzo 
379*f0ea3689SLuigi Rizzo 	if (netmap_verbose)
380f9790aebSLuigi Rizzo 		D("cdev %p foff %jd size %jd objp %p prot %d", cdev,
381f9790aebSLuigi Rizzo 		    (intmax_t )*foff, (intmax_t )objsize, objp, prot);
382f9790aebSLuigi Rizzo 
383f9790aebSLuigi Rizzo 	vmh = malloc(sizeof(struct netmap_vm_handle_t), M_DEVBUF,
384f9790aebSLuigi Rizzo 			      M_NOWAIT | M_ZERO);
385f9790aebSLuigi Rizzo 	if (vmh == NULL)
386f9790aebSLuigi Rizzo 		return ENOMEM;
387f9790aebSLuigi Rizzo 	vmh->dev = cdev;
388f9790aebSLuigi Rizzo 
389f9790aebSLuigi Rizzo 	NMG_LOCK();
390f9790aebSLuigi Rizzo 	error = devfs_get_cdevpriv((void**)&priv);
391f9790aebSLuigi Rizzo 	if (error)
392f9790aebSLuigi Rizzo 		goto err_unlock;
393f9790aebSLuigi Rizzo 	vmh->priv = priv;
394f9790aebSLuigi Rizzo 	priv->np_refcount++;
395f9790aebSLuigi Rizzo 	NMG_UNLOCK();
396f9790aebSLuigi Rizzo 
397f9790aebSLuigi Rizzo 	error = netmap_get_memory(priv);
398f9790aebSLuigi Rizzo 	if (error)
399f9790aebSLuigi Rizzo 		goto err_deref;
400f9790aebSLuigi Rizzo 
401f9790aebSLuigi Rizzo 	obj = cdev_pager_allocate(vmh, OBJT_DEVICE,
402f9790aebSLuigi Rizzo 		&netmap_cdev_pager_ops, objsize, prot,
403f9790aebSLuigi Rizzo 		*foff, NULL);
404f9790aebSLuigi Rizzo 	if (obj == NULL) {
405f9790aebSLuigi Rizzo 		D("cdev_pager_allocate failed");
406f9790aebSLuigi Rizzo 		error = EINVAL;
407f9790aebSLuigi Rizzo 		goto err_deref;
408f9790aebSLuigi Rizzo 	}
409f9790aebSLuigi Rizzo 
410f9790aebSLuigi Rizzo 	*objp = obj;
411f9790aebSLuigi Rizzo 	return 0;
412f9790aebSLuigi Rizzo 
413f9790aebSLuigi Rizzo err_deref:
414f9790aebSLuigi Rizzo 	NMG_LOCK();
415f9790aebSLuigi Rizzo 	priv->np_refcount--;
416f9790aebSLuigi Rizzo err_unlock:
417f9790aebSLuigi Rizzo 	NMG_UNLOCK();
418f9790aebSLuigi Rizzo // err:
419f9790aebSLuigi Rizzo 	free(vmh, M_DEVBUF);
420f9790aebSLuigi Rizzo 	return error;
421f9790aebSLuigi Rizzo }
422f9790aebSLuigi Rizzo 
423f9790aebSLuigi Rizzo 
424f9790aebSLuigi Rizzo // XXX can we remove this ?
425f9790aebSLuigi Rizzo static int
426f9790aebSLuigi Rizzo netmap_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
427f9790aebSLuigi Rizzo {
428f9790aebSLuigi Rizzo 	if (netmap_verbose)
429f9790aebSLuigi Rizzo 		D("dev %p fflag 0x%x devtype %d td %p",
430f9790aebSLuigi Rizzo 			dev, fflag, devtype, td);
431f9790aebSLuigi Rizzo 	return 0;
432f9790aebSLuigi Rizzo }
433f9790aebSLuigi Rizzo 
434f9790aebSLuigi Rizzo 
435f9790aebSLuigi Rizzo static int
436f9790aebSLuigi Rizzo netmap_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
437f9790aebSLuigi Rizzo {
438f9790aebSLuigi Rizzo 	struct netmap_priv_d *priv;
439f9790aebSLuigi Rizzo 	int error;
440f9790aebSLuigi Rizzo 
441f9790aebSLuigi Rizzo 	(void)dev;
442f9790aebSLuigi Rizzo 	(void)oflags;
443f9790aebSLuigi Rizzo 	(void)devtype;
444f9790aebSLuigi Rizzo 	(void)td;
445f9790aebSLuigi Rizzo 
446f9790aebSLuigi Rizzo 	// XXX wait or nowait ?
447f9790aebSLuigi Rizzo 	priv = malloc(sizeof(struct netmap_priv_d), M_DEVBUF,
448f9790aebSLuigi Rizzo 			      M_NOWAIT | M_ZERO);
449f9790aebSLuigi Rizzo 	if (priv == NULL)
450f9790aebSLuigi Rizzo 		return ENOMEM;
451f9790aebSLuigi Rizzo 
452f9790aebSLuigi Rizzo 	error = devfs_set_cdevpriv(priv, netmap_dtor);
453f9790aebSLuigi Rizzo 	if (error)
454f9790aebSLuigi Rizzo 	        return error;
455f9790aebSLuigi Rizzo 
456f9790aebSLuigi Rizzo 	priv->np_refcount = 1;
457f9790aebSLuigi Rizzo 
458f9790aebSLuigi Rizzo 	return 0;
459f9790aebSLuigi Rizzo }
460f9790aebSLuigi Rizzo 
461*f0ea3689SLuigi Rizzo /******************** kqueue support ****************/
462*f0ea3689SLuigi Rizzo 
463*f0ea3689SLuigi Rizzo /*
464*f0ea3689SLuigi Rizzo  * The OS_selwakeup also needs to issue a KNOTE_UNLOCKED.
465*f0ea3689SLuigi Rizzo  * We use a non-zero argument to distinguish the call from the one
466*f0ea3689SLuigi Rizzo  * in kevent_scan() which instead also needs to run netmap_poll().
467*f0ea3689SLuigi Rizzo  * The knote uses a global mutex for the time being. We might
468*f0ea3689SLuigi Rizzo  * try to reuse the one in the si, but it is not allocated
469*f0ea3689SLuigi Rizzo  * permanently so it might be a bit tricky.
470*f0ea3689SLuigi Rizzo  *
471*f0ea3689SLuigi Rizzo  * The *kqfilter function registers one or another f_event
472*f0ea3689SLuigi Rizzo  * depending on read or write mode.
473*f0ea3689SLuigi Rizzo  * In the call to f_event() td_fpop is NULL so any child function
474*f0ea3689SLuigi Rizzo  * calling devfs_get_cdevpriv() would fail - and we need it in
475*f0ea3689SLuigi Rizzo  * netmap_poll(). As a workaround we store priv into kn->kn_hook
476*f0ea3689SLuigi Rizzo  * and pass it as first argument to netmap_poll(), which then
477*f0ea3689SLuigi Rizzo  * uses the failure to tell that we are called from f_event()
478*f0ea3689SLuigi Rizzo  * and do not need the selrecord().
479*f0ea3689SLuigi Rizzo  */
480*f0ea3689SLuigi Rizzo 
481*f0ea3689SLuigi Rizzo void freebsd_selwakeup(struct selinfo *si, int pri);
482*f0ea3689SLuigi Rizzo 
483*f0ea3689SLuigi Rizzo void
484*f0ea3689SLuigi Rizzo freebsd_selwakeup(struct selinfo *si, int pri)
485*f0ea3689SLuigi Rizzo {
486*f0ea3689SLuigi Rizzo 	if (netmap_verbose)
487*f0ea3689SLuigi Rizzo 		D("on knote %p", &si->si_note);
488*f0ea3689SLuigi Rizzo 	selwakeuppri(si, pri);
489*f0ea3689SLuigi Rizzo 	/* use a non-zero hint to tell the notification from the
490*f0ea3689SLuigi Rizzo 	 * call done in kqueue_scan() which uses 0
491*f0ea3689SLuigi Rizzo 	 */
492*f0ea3689SLuigi Rizzo 	KNOTE_UNLOCKED(&si->si_note, 0x100 /* notification */);
493*f0ea3689SLuigi Rizzo }
494*f0ea3689SLuigi Rizzo 
495*f0ea3689SLuigi Rizzo static void
496*f0ea3689SLuigi Rizzo netmap_knrdetach(struct knote *kn)
497*f0ea3689SLuigi Rizzo {
498*f0ea3689SLuigi Rizzo 	struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook;
499*f0ea3689SLuigi Rizzo 	struct selinfo *si = priv->np_rxsi;
500*f0ea3689SLuigi Rizzo 
501*f0ea3689SLuigi Rizzo 	D("remove selinfo %p", si);
502*f0ea3689SLuigi Rizzo 	knlist_remove(&si->si_note, kn, 0);
503*f0ea3689SLuigi Rizzo }
504*f0ea3689SLuigi Rizzo 
505*f0ea3689SLuigi Rizzo static void
506*f0ea3689SLuigi Rizzo netmap_knwdetach(struct knote *kn)
507*f0ea3689SLuigi Rizzo {
508*f0ea3689SLuigi Rizzo 	struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook;
509*f0ea3689SLuigi Rizzo 	struct selinfo *si = priv->np_txsi;
510*f0ea3689SLuigi Rizzo 
511*f0ea3689SLuigi Rizzo 	D("remove selinfo %p", si);
512*f0ea3689SLuigi Rizzo 	knlist_remove(&si->si_note, kn, 0);
513*f0ea3689SLuigi Rizzo }
514*f0ea3689SLuigi Rizzo 
515*f0ea3689SLuigi Rizzo /*
516*f0ea3689SLuigi Rizzo  * callback from notifies (generated externally) and our
517*f0ea3689SLuigi Rizzo  * calls to kevent(). The former we just return 1 (ready)
518*f0ea3689SLuigi Rizzo  * since we do not know better.
519*f0ea3689SLuigi Rizzo  * In the latter we call netmap_poll and return 0/1 accordingly.
520*f0ea3689SLuigi Rizzo  */
521*f0ea3689SLuigi Rizzo static int
522*f0ea3689SLuigi Rizzo netmap_knrw(struct knote *kn, long hint, int events)
523*f0ea3689SLuigi Rizzo {
524*f0ea3689SLuigi Rizzo 	struct netmap_priv_d *priv;
525*f0ea3689SLuigi Rizzo 	int revents;
526*f0ea3689SLuigi Rizzo 
527*f0ea3689SLuigi Rizzo 	if (hint != 0) {
528*f0ea3689SLuigi Rizzo 		ND(5, "call from notify");
529*f0ea3689SLuigi Rizzo 		return 1; /* assume we are ready */
530*f0ea3689SLuigi Rizzo 	}
531*f0ea3689SLuigi Rizzo 	priv = kn->kn_hook;
532*f0ea3689SLuigi Rizzo 	/* the notification may come from an external thread,
533*f0ea3689SLuigi Rizzo 	 * in which case we do not want to run the netmap_poll
534*f0ea3689SLuigi Rizzo 	 * This should be filtered above, but check just in case.
535*f0ea3689SLuigi Rizzo 	 */
536*f0ea3689SLuigi Rizzo 	if (curthread != priv->np_td) { /* should not happen */
537*f0ea3689SLuigi Rizzo 		RD(5, "curthread changed %p %p", curthread, priv->np_td);
538*f0ea3689SLuigi Rizzo 		return 1;
539*f0ea3689SLuigi Rizzo 	} else {
540*f0ea3689SLuigi Rizzo 		revents = netmap_poll((void *)priv, events, curthread);
541*f0ea3689SLuigi Rizzo 		return (events & revents) ? 1 : 0;
542*f0ea3689SLuigi Rizzo 	}
543*f0ea3689SLuigi Rizzo }
544*f0ea3689SLuigi Rizzo 
545*f0ea3689SLuigi Rizzo static int
546*f0ea3689SLuigi Rizzo netmap_knread(struct knote *kn, long hint)
547*f0ea3689SLuigi Rizzo {
548*f0ea3689SLuigi Rizzo 	return netmap_knrw(kn, hint, POLLIN);
549*f0ea3689SLuigi Rizzo }
550*f0ea3689SLuigi Rizzo 
551*f0ea3689SLuigi Rizzo static int
552*f0ea3689SLuigi Rizzo netmap_knwrite(struct knote *kn, long hint)
553*f0ea3689SLuigi Rizzo {
554*f0ea3689SLuigi Rizzo 	return netmap_knrw(kn, hint, POLLOUT);
555*f0ea3689SLuigi Rizzo }
556*f0ea3689SLuigi Rizzo 
557*f0ea3689SLuigi Rizzo static struct filterops netmap_rfiltops = {
558*f0ea3689SLuigi Rizzo 	.f_isfd = 1,
559*f0ea3689SLuigi Rizzo 	.f_detach = netmap_knrdetach,
560*f0ea3689SLuigi Rizzo 	.f_event = netmap_knread,
561*f0ea3689SLuigi Rizzo };
562*f0ea3689SLuigi Rizzo 
563*f0ea3689SLuigi Rizzo static struct filterops netmap_wfiltops = {
564*f0ea3689SLuigi Rizzo 	.f_isfd = 1,
565*f0ea3689SLuigi Rizzo 	.f_detach = netmap_knwdetach,
566*f0ea3689SLuigi Rizzo 	.f_event = netmap_knwrite,
567*f0ea3689SLuigi Rizzo };
568*f0ea3689SLuigi Rizzo 
569*f0ea3689SLuigi Rizzo 
570*f0ea3689SLuigi Rizzo /*
571*f0ea3689SLuigi Rizzo  * This is called when a thread invokes kevent() to record
572*f0ea3689SLuigi Rizzo  * a change in the configuration of the kqueue().
573*f0ea3689SLuigi Rizzo  * The 'priv' should be the same as in the netmap device.
574*f0ea3689SLuigi Rizzo  */
575*f0ea3689SLuigi Rizzo static int
576*f0ea3689SLuigi Rizzo netmap_kqfilter(struct cdev *dev, struct knote *kn)
577*f0ea3689SLuigi Rizzo {
578*f0ea3689SLuigi Rizzo 	struct netmap_priv_d *priv;
579*f0ea3689SLuigi Rizzo 	int error;
580*f0ea3689SLuigi Rizzo 	struct netmap_adapter *na;
581*f0ea3689SLuigi Rizzo 	struct selinfo *si;
582*f0ea3689SLuigi Rizzo 	int ev = kn->kn_filter;
583*f0ea3689SLuigi Rizzo 
584*f0ea3689SLuigi Rizzo 	if (ev != EVFILT_READ && ev != EVFILT_WRITE) {
585*f0ea3689SLuigi Rizzo 		D("bad filter request %d", ev);
586*f0ea3689SLuigi Rizzo 		return 1;
587*f0ea3689SLuigi Rizzo 	}
588*f0ea3689SLuigi Rizzo 	error = devfs_get_cdevpriv((void**)&priv);
589*f0ea3689SLuigi Rizzo 	if (error) {
590*f0ea3689SLuigi Rizzo 		D("device not yet setup");
591*f0ea3689SLuigi Rizzo 		return 1;
592*f0ea3689SLuigi Rizzo 	}
593*f0ea3689SLuigi Rizzo 	na = priv->np_na;
594*f0ea3689SLuigi Rizzo 	if (na == NULL) {
595*f0ea3689SLuigi Rizzo 		D("no netmap adapter for this file descriptor");
596*f0ea3689SLuigi Rizzo 		return 1;
597*f0ea3689SLuigi Rizzo 	}
598*f0ea3689SLuigi Rizzo 	/* the si is indicated in the priv */
599*f0ea3689SLuigi Rizzo 	si = (ev == EVFILT_WRITE) ? priv->np_txsi : priv->np_rxsi;
600*f0ea3689SLuigi Rizzo 	// XXX lock(priv) ?
601*f0ea3689SLuigi Rizzo 	kn->kn_fop = (ev == EVFILT_WRITE) ?
602*f0ea3689SLuigi Rizzo 		&netmap_wfiltops : &netmap_rfiltops;
603*f0ea3689SLuigi Rizzo 	kn->kn_hook = priv;
604*f0ea3689SLuigi Rizzo 	knlist_add(&si->si_note, kn, 1);
605*f0ea3689SLuigi Rizzo 	// XXX unlock(priv)
606*f0ea3689SLuigi Rizzo 	ND("register %p %s td %p priv %p kn %p np_nifp %p kn_fp/fpop %s",
607*f0ea3689SLuigi Rizzo 		na, na->ifp->if_xname, curthread, priv, kn,
608*f0ea3689SLuigi Rizzo 		priv->np_nifp,
609*f0ea3689SLuigi Rizzo 		kn->kn_fp == curthread->td_fpop ? "match" : "MISMATCH");
610*f0ea3689SLuigi Rizzo 	return 0;
611*f0ea3689SLuigi Rizzo }
612f9790aebSLuigi Rizzo 
613f9790aebSLuigi Rizzo struct cdevsw netmap_cdevsw = {
614f9790aebSLuigi Rizzo 	.d_version = D_VERSION,
615f9790aebSLuigi Rizzo 	.d_name = "netmap",
616f9790aebSLuigi Rizzo 	.d_open = netmap_open,
617f9790aebSLuigi Rizzo 	.d_mmap_single = netmap_mmap_single,
618f9790aebSLuigi Rizzo 	.d_ioctl = netmap_ioctl,
619f9790aebSLuigi Rizzo 	.d_poll = netmap_poll,
620*f0ea3689SLuigi Rizzo 	.d_kqfilter = netmap_kqfilter,
621f9790aebSLuigi Rizzo 	.d_close = netmap_close,
622f9790aebSLuigi Rizzo };
623*f0ea3689SLuigi Rizzo /*--- end of kqueue support ----*/
624f9790aebSLuigi Rizzo 
625f9790aebSLuigi Rizzo /*
626f9790aebSLuigi Rizzo  * Kernel entry point.
627f9790aebSLuigi Rizzo  *
628f9790aebSLuigi Rizzo  * Initialize/finalize the module and return.
629f9790aebSLuigi Rizzo  *
630f9790aebSLuigi Rizzo  * Return 0 on success, errno on failure.
631f9790aebSLuigi Rizzo  */
632f9790aebSLuigi Rizzo static int
633f9790aebSLuigi Rizzo netmap_loader(__unused struct module *module, int event, __unused void *arg)
634f9790aebSLuigi Rizzo {
635f9790aebSLuigi Rizzo 	int error = 0;
636f9790aebSLuigi Rizzo 
637f9790aebSLuigi Rizzo 	switch (event) {
638f9790aebSLuigi Rizzo 	case MOD_LOAD:
639f9790aebSLuigi Rizzo 		error = netmap_init();
640f9790aebSLuigi Rizzo 		break;
641f9790aebSLuigi Rizzo 
642f9790aebSLuigi Rizzo 	case MOD_UNLOAD:
643f9790aebSLuigi Rizzo 		netmap_fini();
644f9790aebSLuigi Rizzo 		break;
645f9790aebSLuigi Rizzo 
646f9790aebSLuigi Rizzo 	default:
647f9790aebSLuigi Rizzo 		error = EOPNOTSUPP;
648f9790aebSLuigi Rizzo 		break;
649f9790aebSLuigi Rizzo 	}
650f9790aebSLuigi Rizzo 
651f9790aebSLuigi Rizzo 	return (error);
652f9790aebSLuigi Rizzo }
653f9790aebSLuigi Rizzo 
654f9790aebSLuigi Rizzo 
655f9790aebSLuigi Rizzo DEV_MODULE(netmap, netmap_loader, NULL);
656