xref: /freebsd-12.1/sys/dev/netmap/netmap_kloop.c (revision b321acab)
1*b321acabSVincenzo Maffione /*
2*b321acabSVincenzo Maffione  * Copyright (C) 2016-2018 Vincenzo Maffione
3*b321acabSVincenzo Maffione  * Copyright (C) 2015 Stefano Garzarella
4*b321acabSVincenzo Maffione  * All rights reserved.
5*b321acabSVincenzo Maffione  *
6*b321acabSVincenzo Maffione  * Redistribution and use in source and binary forms, with or without
7*b321acabSVincenzo Maffione  * modification, are permitted provided that the following conditions
8*b321acabSVincenzo Maffione  * are met:
9*b321acabSVincenzo Maffione  *   1. Redistributions of source code must retain the above copyright
10*b321acabSVincenzo Maffione  *      notice, this list of conditions and the following disclaimer.
11*b321acabSVincenzo Maffione  *   2. Redistributions in binary form must reproduce the above copyright
12*b321acabSVincenzo Maffione  *      notice, this list of conditions and the following disclaimer in the
13*b321acabSVincenzo Maffione  *      documentation and/or other materials provided with the distribution.
14*b321acabSVincenzo Maffione  *
15*b321acabSVincenzo Maffione  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*b321acabSVincenzo Maffione  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*b321acabSVincenzo Maffione  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*b321acabSVincenzo Maffione  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*b321acabSVincenzo Maffione  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*b321acabSVincenzo Maffione  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*b321acabSVincenzo Maffione  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*b321acabSVincenzo Maffione  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*b321acabSVincenzo Maffione  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*b321acabSVincenzo Maffione  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*b321acabSVincenzo Maffione  * SUCH DAMAGE.
26*b321acabSVincenzo Maffione  *
27*b321acabSVincenzo Maffione  * $FreeBSD$
28*b321acabSVincenzo Maffione  */
29*b321acabSVincenzo Maffione 
30*b321acabSVincenzo Maffione /*
31*b321acabSVincenzo Maffione  * common headers
32*b321acabSVincenzo Maffione  */
33*b321acabSVincenzo Maffione #if defined(__FreeBSD__)
34*b321acabSVincenzo Maffione #include <sys/cdefs.h>
35*b321acabSVincenzo Maffione #include <sys/param.h>
36*b321acabSVincenzo Maffione #include <sys/kernel.h>
37*b321acabSVincenzo Maffione #include <sys/types.h>
38*b321acabSVincenzo Maffione #include <sys/selinfo.h>
39*b321acabSVincenzo Maffione #include <sys/socket.h>
40*b321acabSVincenzo Maffione #include <net/if.h>
41*b321acabSVincenzo Maffione #include <net/if_var.h>
42*b321acabSVincenzo Maffione #include <machine/bus.h>
43*b321acabSVincenzo Maffione 
44*b321acabSVincenzo Maffione #define usleep_range(_1, _2) \
45*b321acabSVincenzo Maffione         pause_sbt("sync-kloop-sleep", SBT_1US * _1, SBT_1US * 1, C_ABSOLUTE)
46*b321acabSVincenzo Maffione 
47*b321acabSVincenzo Maffione #elif defined(linux)
48*b321acabSVincenzo Maffione #include <bsd_glue.h>
49*b321acabSVincenzo Maffione #include <linux/file.h>
50*b321acabSVincenzo Maffione #include <linux/eventfd.h>
51*b321acabSVincenzo Maffione #endif
52*b321acabSVincenzo Maffione 
53*b321acabSVincenzo Maffione #include <net/netmap.h>
54*b321acabSVincenzo Maffione #include <dev/netmap/netmap_kern.h>
55*b321acabSVincenzo Maffione #include <net/netmap_virt.h>
56*b321acabSVincenzo Maffione #include <dev/netmap/netmap_mem2.h>
57*b321acabSVincenzo Maffione 
58*b321acabSVincenzo Maffione /* Support for eventfd-based notifications. */
59*b321acabSVincenzo Maffione #if defined(linux)
60*b321acabSVincenzo Maffione #define SYNC_KLOOP_POLL
61*b321acabSVincenzo Maffione #endif
62*b321acabSVincenzo Maffione 
63*b321acabSVincenzo Maffione /* Write kring pointers (hwcur, hwtail) to the CSB.
64*b321acabSVincenzo Maffione  * This routine is coupled with ptnetmap_guest_read_kring_csb(). */
65*b321acabSVincenzo Maffione static inline void
66*b321acabSVincenzo Maffione sync_kloop_kernel_write(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
67*b321acabSVincenzo Maffione 			   uint32_t hwtail)
68*b321acabSVincenzo Maffione {
69*b321acabSVincenzo Maffione 	/*
70*b321acabSVincenzo Maffione 	 * The same scheme used in ptnetmap_guest_write_kring_csb() applies here.
71*b321acabSVincenzo Maffione 	 * We allow the application to read a value of hwcur more recent than the value
72*b321acabSVincenzo Maffione 	 * of hwtail, since this would anyway result in a consistent view of the
73*b321acabSVincenzo Maffione 	 * ring state (and hwcur can never wraparound hwtail, since hwcur must be
74*b321acabSVincenzo Maffione 	 * behind head).
75*b321acabSVincenzo Maffione 	 *
76*b321acabSVincenzo Maffione 	 * The following memory barrier scheme is used to make this happen:
77*b321acabSVincenzo Maffione 	 *
78*b321acabSVincenzo Maffione 	 *          Application          Kernel
79*b321acabSVincenzo Maffione 	 *
80*b321acabSVincenzo Maffione 	 *          STORE(hwcur)         LOAD(hwtail)
81*b321acabSVincenzo Maffione 	 *          mb() <-------------> mb()
82*b321acabSVincenzo Maffione 	 *          STORE(hwtail)        LOAD(hwcur)
83*b321acabSVincenzo Maffione 	 */
84*b321acabSVincenzo Maffione 	CSB_WRITE(ptr, hwcur, hwcur);
85*b321acabSVincenzo Maffione 	nm_stst_barrier();
86*b321acabSVincenzo Maffione 	CSB_WRITE(ptr, hwtail, hwtail);
87*b321acabSVincenzo Maffione }
88*b321acabSVincenzo Maffione 
89*b321acabSVincenzo Maffione /* Read kring pointers (head, cur, sync_flags) from the CSB.
90*b321acabSVincenzo Maffione  * This routine is coupled with ptnetmap_guest_write_kring_csb(). */
91*b321acabSVincenzo Maffione static inline void
92*b321acabSVincenzo Maffione sync_kloop_kernel_read(struct nm_csb_atok __user *ptr,
93*b321acabSVincenzo Maffione 			  struct netmap_ring *shadow_ring,
94*b321acabSVincenzo Maffione 			  uint32_t num_slots)
95*b321acabSVincenzo Maffione {
96*b321acabSVincenzo Maffione 	/*
97*b321acabSVincenzo Maffione 	 * We place a memory barrier to make sure that the update of head never
98*b321acabSVincenzo Maffione 	 * overtakes the update of cur.
99*b321acabSVincenzo Maffione 	 * (see explanation in ptnetmap_guest_write_kring_csb).
100*b321acabSVincenzo Maffione 	 */
101*b321acabSVincenzo Maffione 	CSB_READ(ptr, head, shadow_ring->head);
102*b321acabSVincenzo Maffione 	nm_stst_barrier();
103*b321acabSVincenzo Maffione 	CSB_READ(ptr, cur, shadow_ring->cur);
104*b321acabSVincenzo Maffione 	CSB_READ(ptr, sync_flags, shadow_ring->flags);
105*b321acabSVincenzo Maffione }
106*b321acabSVincenzo Maffione 
107*b321acabSVincenzo Maffione /* Enable or disable application --> kernel kicks. */
108*b321acabSVincenzo Maffione static inline void
109*b321acabSVincenzo Maffione csb_ktoa_kick_enable(struct nm_csb_ktoa __user *csb_ktoa, uint32_t val)
110*b321acabSVincenzo Maffione {
111*b321acabSVincenzo Maffione 	CSB_WRITE(csb_ktoa, kern_need_kick, val);
112*b321acabSVincenzo Maffione }
113*b321acabSVincenzo Maffione 
114*b321acabSVincenzo Maffione /* Are application interrupt enabled or disabled? */
115*b321acabSVincenzo Maffione static inline uint32_t
116*b321acabSVincenzo Maffione csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
117*b321acabSVincenzo Maffione {
118*b321acabSVincenzo Maffione 	uint32_t v;
119*b321acabSVincenzo Maffione 
120*b321acabSVincenzo Maffione 	CSB_READ(csb_atok, appl_need_kick, v);
121*b321acabSVincenzo Maffione 
122*b321acabSVincenzo Maffione 	return v;
123*b321acabSVincenzo Maffione }
124*b321acabSVincenzo Maffione 
125*b321acabSVincenzo Maffione static inline void
126*b321acabSVincenzo Maffione sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
127*b321acabSVincenzo Maffione {
128*b321acabSVincenzo Maffione 	nm_prinf("%s - name: %s hwcur: %d hwtail: %d "
129*b321acabSVincenzo Maffione 		"rhead: %d rcur: %d rtail: %d",
130*b321acabSVincenzo Maffione 		title, kring->name, kring->nr_hwcur, kring->nr_hwtail,
131*b321acabSVincenzo Maffione 		kring->rhead, kring->rcur, kring->rtail);
132*b321acabSVincenzo Maffione }
133*b321acabSVincenzo Maffione 
134*b321acabSVincenzo Maffione struct sync_kloop_ring_args {
135*b321acabSVincenzo Maffione 	struct netmap_kring *kring;
136*b321acabSVincenzo Maffione 	struct nm_csb_atok *csb_atok;
137*b321acabSVincenzo Maffione 	struct nm_csb_ktoa *csb_ktoa;
138*b321acabSVincenzo Maffione #ifdef SYNC_KLOOP_POLL
139*b321acabSVincenzo Maffione 	struct eventfd_ctx *irq_ctx;
140*b321acabSVincenzo Maffione #endif /* SYNC_KLOOP_POLL */
141*b321acabSVincenzo Maffione };
142*b321acabSVincenzo Maffione 
143*b321acabSVincenzo Maffione static void
144*b321acabSVincenzo Maffione netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
145*b321acabSVincenzo Maffione {
146*b321acabSVincenzo Maffione 	struct netmap_kring *kring = a->kring;
147*b321acabSVincenzo Maffione 	struct nm_csb_atok *csb_atok = a->csb_atok;
148*b321acabSVincenzo Maffione 	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
149*b321acabSVincenzo Maffione 	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
150*b321acabSVincenzo Maffione 	bool more_txspace = false;
151*b321acabSVincenzo Maffione 	uint32_t num_slots;
152*b321acabSVincenzo Maffione 	int batch;
153*b321acabSVincenzo Maffione 
154*b321acabSVincenzo Maffione 	num_slots = kring->nkr_num_slots;
155*b321acabSVincenzo Maffione 
156*b321acabSVincenzo Maffione 	/* Disable application --> kernel notifications. */
157*b321acabSVincenzo Maffione 	csb_ktoa_kick_enable(csb_ktoa, 0);
158*b321acabSVincenzo Maffione 	/* Copy the application kring pointers from the CSB */
159*b321acabSVincenzo Maffione 	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
160*b321acabSVincenzo Maffione 
161*b321acabSVincenzo Maffione 	for (;;) {
162*b321acabSVincenzo Maffione 		batch = shadow_ring.head - kring->nr_hwcur;
163*b321acabSVincenzo Maffione 		if (batch < 0)
164*b321acabSVincenzo Maffione 			batch += num_slots;
165*b321acabSVincenzo Maffione 
166*b321acabSVincenzo Maffione #ifdef PTN_TX_BATCH_LIM
167*b321acabSVincenzo Maffione 		if (batch > PTN_TX_BATCH_LIM(num_slots)) {
168*b321acabSVincenzo Maffione 			/* If application moves ahead too fast, let's cut the move so
169*b321acabSVincenzo Maffione 			 * that we don't exceed our batch limit. */
170*b321acabSVincenzo Maffione 			uint32_t head_lim = kring->nr_hwcur + PTN_TX_BATCH_LIM(num_slots);
171*b321acabSVincenzo Maffione 
172*b321acabSVincenzo Maffione 			if (head_lim >= num_slots)
173*b321acabSVincenzo Maffione 				head_lim -= num_slots;
174*b321acabSVincenzo Maffione 			nm_prdis(1, "batch: %d head: %d head_lim: %d", batch, shadow_ring.head,
175*b321acabSVincenzo Maffione 					head_lim);
176*b321acabSVincenzo Maffione 			shadow_ring.head = head_lim;
177*b321acabSVincenzo Maffione 			batch = PTN_TX_BATCH_LIM(num_slots);
178*b321acabSVincenzo Maffione 		}
179*b321acabSVincenzo Maffione #endif /* PTN_TX_BATCH_LIM */
180*b321acabSVincenzo Maffione 
181*b321acabSVincenzo Maffione 		if (nm_kr_txspace(kring) <= (num_slots >> 1)) {
182*b321acabSVincenzo Maffione 			shadow_ring.flags |= NAF_FORCE_RECLAIM;
183*b321acabSVincenzo Maffione 		}
184*b321acabSVincenzo Maffione 
185*b321acabSVincenzo Maffione 		/* Netmap prologue */
186*b321acabSVincenzo Maffione 		shadow_ring.tail = kring->rtail;
187*b321acabSVincenzo Maffione 		if (unlikely(nm_txsync_prologue(kring, &shadow_ring) >= num_slots)) {
188*b321acabSVincenzo Maffione 			/* Reinit ring and enable notifications. */
189*b321acabSVincenzo Maffione 			netmap_ring_reinit(kring);
190*b321acabSVincenzo Maffione 			csb_ktoa_kick_enable(csb_ktoa, 1);
191*b321acabSVincenzo Maffione 			break;
192*b321acabSVincenzo Maffione 		}
193*b321acabSVincenzo Maffione 
194*b321acabSVincenzo Maffione 		if (unlikely(netmap_debug & NM_DEBUG_TXSYNC)) {
195*b321acabSVincenzo Maffione 			sync_kloop_kring_dump("pre txsync", kring);
196*b321acabSVincenzo Maffione 		}
197*b321acabSVincenzo Maffione 
198*b321acabSVincenzo Maffione 		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
199*b321acabSVincenzo Maffione 			/* Reenable notifications. */
200*b321acabSVincenzo Maffione 			csb_ktoa_kick_enable(csb_ktoa, 1);
201*b321acabSVincenzo Maffione 			nm_prerr("txsync() failed");
202*b321acabSVincenzo Maffione 			break;
203*b321acabSVincenzo Maffione 		}
204*b321acabSVincenzo Maffione 
205*b321acabSVincenzo Maffione 		/*
206*b321acabSVincenzo Maffione 		 * Finalize
207*b321acabSVincenzo Maffione 		 * Copy kernel hwcur and hwtail into the CSB for the application sync(), and
208*b321acabSVincenzo Maffione 		 * do the nm_sync_finalize.
209*b321acabSVincenzo Maffione 		 */
210*b321acabSVincenzo Maffione 		sync_kloop_kernel_write(csb_ktoa, kring->nr_hwcur,
211*b321acabSVincenzo Maffione 				kring->nr_hwtail);
212*b321acabSVincenzo Maffione 		if (kring->rtail != kring->nr_hwtail) {
213*b321acabSVincenzo Maffione 			/* Some more room available in the parent adapter. */
214*b321acabSVincenzo Maffione 			kring->rtail = kring->nr_hwtail;
215*b321acabSVincenzo Maffione 			more_txspace = true;
216*b321acabSVincenzo Maffione 		}
217*b321acabSVincenzo Maffione 
218*b321acabSVincenzo Maffione 		if (unlikely(netmap_debug & NM_DEBUG_TXSYNC)) {
219*b321acabSVincenzo Maffione 			sync_kloop_kring_dump("post txsync", kring);
220*b321acabSVincenzo Maffione 		}
221*b321acabSVincenzo Maffione 
222*b321acabSVincenzo Maffione 		/* Interrupt the application if needed. */
223*b321acabSVincenzo Maffione #ifdef SYNC_KLOOP_POLL
224*b321acabSVincenzo Maffione 		if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
225*b321acabSVincenzo Maffione 			/* Disable application kick to avoid sending unnecessary kicks */
226*b321acabSVincenzo Maffione 			eventfd_signal(a->irq_ctx, 1);
227*b321acabSVincenzo Maffione 			more_txspace = false;
228*b321acabSVincenzo Maffione 		}
229*b321acabSVincenzo Maffione #endif /* SYNC_KLOOP_POLL */
230*b321acabSVincenzo Maffione 
231*b321acabSVincenzo Maffione 		/* Read CSB to see if there is more work to do. */
232*b321acabSVincenzo Maffione 		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
233*b321acabSVincenzo Maffione 		if (shadow_ring.head == kring->rhead) {
234*b321acabSVincenzo Maffione 			/*
235*b321acabSVincenzo Maffione 			 * No more packets to transmit. We enable notifications and
236*b321acabSVincenzo Maffione 			 * go to sleep, waiting for a kick from the application when new
237*b321acabSVincenzo Maffione 			 * new slots are ready for transmission.
238*b321acabSVincenzo Maffione 			 */
239*b321acabSVincenzo Maffione 			/* Reenable notifications. */
240*b321acabSVincenzo Maffione 			csb_ktoa_kick_enable(csb_ktoa, 1);
241*b321acabSVincenzo Maffione 			/* Doublecheck. */
242*b321acabSVincenzo Maffione 			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
243*b321acabSVincenzo Maffione 			if (shadow_ring.head != kring->rhead) {
244*b321acabSVincenzo Maffione 				/* We won the race condition, there are more packets to
245*b321acabSVincenzo Maffione 				 * transmit. Disable notifications and do another cycle */
246*b321acabSVincenzo Maffione 				csb_ktoa_kick_enable(csb_ktoa, 0);
247*b321acabSVincenzo Maffione 				continue;
248*b321acabSVincenzo Maffione 			}
249*b321acabSVincenzo Maffione 			break;
250*b321acabSVincenzo Maffione 		}
251*b321acabSVincenzo Maffione 
252*b321acabSVincenzo Maffione 		if (nm_kr_txempty(kring)) {
253*b321acabSVincenzo Maffione 			/* No more available TX slots. We stop waiting for a notification
254*b321acabSVincenzo Maffione 			 * from the backend (netmap_tx_irq). */
255*b321acabSVincenzo Maffione 			nm_prdis(1, "TX ring");
256*b321acabSVincenzo Maffione 			break;
257*b321acabSVincenzo Maffione 		}
258*b321acabSVincenzo Maffione 	}
259*b321acabSVincenzo Maffione 
260*b321acabSVincenzo Maffione #ifdef SYNC_KLOOP_POLL
261*b321acabSVincenzo Maffione 	if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
262*b321acabSVincenzo Maffione 		eventfd_signal(a->irq_ctx, 1);
263*b321acabSVincenzo Maffione 	}
264*b321acabSVincenzo Maffione #endif /* SYNC_KLOOP_POLL */
265*b321acabSVincenzo Maffione }
266*b321acabSVincenzo Maffione 
267*b321acabSVincenzo Maffione /* RX cycle without receive any packets */
268*b321acabSVincenzo Maffione #define SYNC_LOOP_RX_DRY_CYCLES_MAX	2
269*b321acabSVincenzo Maffione 
270*b321acabSVincenzo Maffione static inline int
271*b321acabSVincenzo Maffione sync_kloop_norxslots(struct netmap_kring *kring, uint32_t g_head)
272*b321acabSVincenzo Maffione {
273*b321acabSVincenzo Maffione 	return (NM_ACCESS_ONCE(kring->nr_hwtail) == nm_prev(g_head,
274*b321acabSVincenzo Maffione 				kring->nkr_num_slots - 1));
275*b321acabSVincenzo Maffione }
276*b321acabSVincenzo Maffione 
277*b321acabSVincenzo Maffione static void
278*b321acabSVincenzo Maffione netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
279*b321acabSVincenzo Maffione {
280*b321acabSVincenzo Maffione 
281*b321acabSVincenzo Maffione 	struct netmap_kring *kring = a->kring;
282*b321acabSVincenzo Maffione 	struct nm_csb_atok *csb_atok = a->csb_atok;
283*b321acabSVincenzo Maffione 	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
284*b321acabSVincenzo Maffione 	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
285*b321acabSVincenzo Maffione 	int dry_cycles = 0;
286*b321acabSVincenzo Maffione 	bool some_recvd = false;
287*b321acabSVincenzo Maffione 	uint32_t num_slots;
288*b321acabSVincenzo Maffione 
289*b321acabSVincenzo Maffione 	num_slots = kring->nkr_num_slots;
290*b321acabSVincenzo Maffione 
291*b321acabSVincenzo Maffione 	/* Get RX csb_atok and csb_ktoa pointers from the CSB. */
292*b321acabSVincenzo Maffione 	num_slots = kring->nkr_num_slots;
293*b321acabSVincenzo Maffione 
294*b321acabSVincenzo Maffione 	/* Disable notifications. */
295*b321acabSVincenzo Maffione 	csb_ktoa_kick_enable(csb_ktoa, 0);
296*b321acabSVincenzo Maffione 	/* Copy the application kring pointers from the CSB */
297*b321acabSVincenzo Maffione 	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
298*b321acabSVincenzo Maffione 
299*b321acabSVincenzo Maffione 	for (;;) {
300*b321acabSVincenzo Maffione 		uint32_t hwtail;
301*b321acabSVincenzo Maffione 
302*b321acabSVincenzo Maffione 		/* Netmap prologue */
303*b321acabSVincenzo Maffione 		shadow_ring.tail = kring->rtail;
304*b321acabSVincenzo Maffione 		if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) {
305*b321acabSVincenzo Maffione 			/* Reinit ring and enable notifications. */
306*b321acabSVincenzo Maffione 			netmap_ring_reinit(kring);
307*b321acabSVincenzo Maffione 			csb_ktoa_kick_enable(csb_ktoa, 1);
308*b321acabSVincenzo Maffione 			break;
309*b321acabSVincenzo Maffione 		}
310*b321acabSVincenzo Maffione 
311*b321acabSVincenzo Maffione 		if (unlikely(netmap_debug & NM_DEBUG_RXSYNC)) {
312*b321acabSVincenzo Maffione 			sync_kloop_kring_dump("pre rxsync", kring);
313*b321acabSVincenzo Maffione 		}
314*b321acabSVincenzo Maffione 
315*b321acabSVincenzo Maffione 		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
316*b321acabSVincenzo Maffione 			/* Reenable notifications. */
317*b321acabSVincenzo Maffione 			csb_ktoa_kick_enable(csb_ktoa, 1);
318*b321acabSVincenzo Maffione 			nm_prerr("rxsync() failed");
319*b321acabSVincenzo Maffione 			break;
320*b321acabSVincenzo Maffione 		}
321*b321acabSVincenzo Maffione 
322*b321acabSVincenzo Maffione 		/*
323*b321acabSVincenzo Maffione 		 * Finalize
324*b321acabSVincenzo Maffione 		 * Copy kernel hwcur and hwtail into the CSB for the application sync()
325*b321acabSVincenzo Maffione 		 */
326*b321acabSVincenzo Maffione 		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
327*b321acabSVincenzo Maffione 		sync_kloop_kernel_write(csb_ktoa, kring->nr_hwcur, hwtail);
328*b321acabSVincenzo Maffione 		if (kring->rtail != hwtail) {
329*b321acabSVincenzo Maffione 			kring->rtail = hwtail;
330*b321acabSVincenzo Maffione 			some_recvd = true;
331*b321acabSVincenzo Maffione 			dry_cycles = 0;
332*b321acabSVincenzo Maffione 		} else {
333*b321acabSVincenzo Maffione 			dry_cycles++;
334*b321acabSVincenzo Maffione 		}
335*b321acabSVincenzo Maffione 
336*b321acabSVincenzo Maffione 		if (unlikely(netmap_debug & NM_DEBUG_RXSYNC)) {
337*b321acabSVincenzo Maffione 			sync_kloop_kring_dump("post rxsync", kring);
338*b321acabSVincenzo Maffione 		}
339*b321acabSVincenzo Maffione 
340*b321acabSVincenzo Maffione #ifdef SYNC_KLOOP_POLL
341*b321acabSVincenzo Maffione 		/* Interrupt the application if needed. */
342*b321acabSVincenzo Maffione 		if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
343*b321acabSVincenzo Maffione 			/* Disable application kick to avoid sending unnecessary kicks */
344*b321acabSVincenzo Maffione 			eventfd_signal(a->irq_ctx, 1);
345*b321acabSVincenzo Maffione 			some_recvd = false;
346*b321acabSVincenzo Maffione 		}
347*b321acabSVincenzo Maffione #endif /* SYNC_KLOOP_POLL */
348*b321acabSVincenzo Maffione 
349*b321acabSVincenzo Maffione 		/* Read CSB to see if there is more work to do. */
350*b321acabSVincenzo Maffione 		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
351*b321acabSVincenzo Maffione 		if (sync_kloop_norxslots(kring, shadow_ring.head)) {
352*b321acabSVincenzo Maffione 			/*
353*b321acabSVincenzo Maffione 			 * No more slots available for reception. We enable notification and
354*b321acabSVincenzo Maffione 			 * go to sleep, waiting for a kick from the application when new receive
355*b321acabSVincenzo Maffione 			 * slots are available.
356*b321acabSVincenzo Maffione 			 */
357*b321acabSVincenzo Maffione 			/* Reenable notifications. */
358*b321acabSVincenzo Maffione 			csb_ktoa_kick_enable(csb_ktoa, 1);
359*b321acabSVincenzo Maffione 			/* Doublecheck. */
360*b321acabSVincenzo Maffione 			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
361*b321acabSVincenzo Maffione 			if (!sync_kloop_norxslots(kring, shadow_ring.head)) {
362*b321acabSVincenzo Maffione 				/* We won the race condition, more slots are available. Disable
363*b321acabSVincenzo Maffione 				 * notifications and do another cycle. */
364*b321acabSVincenzo Maffione 				csb_ktoa_kick_enable(csb_ktoa, 0);
365*b321acabSVincenzo Maffione 				continue;
366*b321acabSVincenzo Maffione 			}
367*b321acabSVincenzo Maffione 			break;
368*b321acabSVincenzo Maffione 		}
369*b321acabSVincenzo Maffione 
370*b321acabSVincenzo Maffione 		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
371*b321acabSVincenzo Maffione 		if (unlikely(hwtail == kring->rhead ||
372*b321acabSVincenzo Maffione 					dry_cycles >= SYNC_LOOP_RX_DRY_CYCLES_MAX)) {
373*b321acabSVincenzo Maffione 			/* No more packets to be read from the backend. We stop and
374*b321acabSVincenzo Maffione 			 * wait for a notification from the backend (netmap_rx_irq). */
375*b321acabSVincenzo Maffione 			nm_prdis(1, "nr_hwtail: %d rhead: %d dry_cycles: %d",
376*b321acabSVincenzo Maffione 					hwtail, kring->rhead, dry_cycles);
377*b321acabSVincenzo Maffione 			break;
378*b321acabSVincenzo Maffione 		}
379*b321acabSVincenzo Maffione 	}
380*b321acabSVincenzo Maffione 
381*b321acabSVincenzo Maffione 	nm_kr_put(kring);
382*b321acabSVincenzo Maffione 
383*b321acabSVincenzo Maffione #ifdef SYNC_KLOOP_POLL
384*b321acabSVincenzo Maffione 	/* Interrupt the application if needed. */
385*b321acabSVincenzo Maffione 	if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
386*b321acabSVincenzo Maffione 		eventfd_signal(a->irq_ctx, 1);
387*b321acabSVincenzo Maffione 	}
388*b321acabSVincenzo Maffione #endif /* SYNC_KLOOP_POLL */
389*b321acabSVincenzo Maffione }
390*b321acabSVincenzo Maffione 
391*b321acabSVincenzo Maffione #ifdef SYNC_KLOOP_POLL
392*b321acabSVincenzo Maffione struct sync_kloop_poll_entry {
393*b321acabSVincenzo Maffione 	/* Support for receiving notifications from
394*b321acabSVincenzo Maffione 	 * a netmap ring or from the application. */
395*b321acabSVincenzo Maffione 	struct file *filp;
396*b321acabSVincenzo Maffione 	wait_queue_t wait;
397*b321acabSVincenzo Maffione 	wait_queue_head_t *wqh;
398*b321acabSVincenzo Maffione 
399*b321acabSVincenzo Maffione 	/* Support for sending notifications to the application. */
400*b321acabSVincenzo Maffione 	struct eventfd_ctx *irq_ctx;
401*b321acabSVincenzo Maffione 	struct file *irq_filp;
402*b321acabSVincenzo Maffione };
403*b321acabSVincenzo Maffione 
404*b321acabSVincenzo Maffione struct sync_kloop_poll_ctx {
405*b321acabSVincenzo Maffione 	poll_table wait_table;
406*b321acabSVincenzo Maffione 	unsigned int next_entry;
407*b321acabSVincenzo Maffione 	unsigned int num_entries;
408*b321acabSVincenzo Maffione 	struct sync_kloop_poll_entry entries[0];
409*b321acabSVincenzo Maffione };
410*b321acabSVincenzo Maffione 
411*b321acabSVincenzo Maffione static void
412*b321acabSVincenzo Maffione sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
413*b321acabSVincenzo Maffione 				poll_table *pt)
414*b321acabSVincenzo Maffione {
415*b321acabSVincenzo Maffione 	struct sync_kloop_poll_ctx *poll_ctx =
416*b321acabSVincenzo Maffione 		container_of(pt, struct sync_kloop_poll_ctx, wait_table);
417*b321acabSVincenzo Maffione 	struct sync_kloop_poll_entry *entry = poll_ctx->entries +
418*b321acabSVincenzo Maffione 						poll_ctx->next_entry;
419*b321acabSVincenzo Maffione 
420*b321acabSVincenzo Maffione 	BUG_ON(poll_ctx->next_entry >= poll_ctx->num_entries);
421*b321acabSVincenzo Maffione 	entry->wqh = wqh;
422*b321acabSVincenzo Maffione 	entry->filp = file;
423*b321acabSVincenzo Maffione 	/* Use the default wake up function. */
424*b321acabSVincenzo Maffione 	init_waitqueue_entry(&entry->wait, current);
425*b321acabSVincenzo Maffione 	add_wait_queue(wqh, &entry->wait);
426*b321acabSVincenzo Maffione 	poll_ctx->next_entry++;
427*b321acabSVincenzo Maffione }
428*b321acabSVincenzo Maffione #endif  /* SYNC_KLOOP_POLL */
429*b321acabSVincenzo Maffione 
430*b321acabSVincenzo Maffione int
431*b321acabSVincenzo Maffione netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
432*b321acabSVincenzo Maffione {
433*b321acabSVincenzo Maffione 	struct nmreq_sync_kloop_start *req =
434*b321acabSVincenzo Maffione 		(struct nmreq_sync_kloop_start *)(uintptr_t)hdr->nr_body;
435*b321acabSVincenzo Maffione 	struct nmreq_opt_sync_kloop_eventfds *eventfds_opt = NULL;
436*b321acabSVincenzo Maffione #ifdef SYNC_KLOOP_POLL
437*b321acabSVincenzo Maffione 	struct sync_kloop_poll_ctx *poll_ctx = NULL;
438*b321acabSVincenzo Maffione #endif  /* SYNC_KLOOP_POLL */
439*b321acabSVincenzo Maffione 	int num_rx_rings, num_tx_rings, num_rings;
440*b321acabSVincenzo Maffione 	uint32_t sleep_us = req->sleep_us;
441*b321acabSVincenzo Maffione 	struct nm_csb_atok* csb_atok_base;
442*b321acabSVincenzo Maffione 	struct nm_csb_ktoa* csb_ktoa_base;
443*b321acabSVincenzo Maffione 	struct netmap_adapter *na;
444*b321acabSVincenzo Maffione 	struct nmreq_option *opt;
445*b321acabSVincenzo Maffione 	int err = 0;
446*b321acabSVincenzo Maffione 	int i;
447*b321acabSVincenzo Maffione 
448*b321acabSVincenzo Maffione 	if (sleep_us > 1000000) {
449*b321acabSVincenzo Maffione 		/* We do not accept sleeping for more than a second. */
450*b321acabSVincenzo Maffione 		return EINVAL;
451*b321acabSVincenzo Maffione 	}
452*b321acabSVincenzo Maffione 
453*b321acabSVincenzo Maffione 	if (priv->np_nifp == NULL) {
454*b321acabSVincenzo Maffione 		return ENXIO;
455*b321acabSVincenzo Maffione 	}
456*b321acabSVincenzo Maffione 	mb(); /* make sure following reads are not from cache */
457*b321acabSVincenzo Maffione 
458*b321acabSVincenzo Maffione 	na = priv->np_na;
459*b321acabSVincenzo Maffione 	if (!nm_netmap_on(na)) {
460*b321acabSVincenzo Maffione 		return ENXIO;
461*b321acabSVincenzo Maffione 	}
462*b321acabSVincenzo Maffione 
463*b321acabSVincenzo Maffione 	NMG_LOCK();
464*b321acabSVincenzo Maffione 	/* Make sure the application is working in CSB mode. */
465*b321acabSVincenzo Maffione 	if (!priv->np_csb_atok_base || !priv->np_csb_ktoa_base) {
466*b321acabSVincenzo Maffione 		NMG_UNLOCK();
467*b321acabSVincenzo Maffione 		nm_prerr("sync-kloop on %s requires "
468*b321acabSVincenzo Maffione 				"NETMAP_REQ_OPT_CSB option", na->name);
469*b321acabSVincenzo Maffione 		return EINVAL;
470*b321acabSVincenzo Maffione 	}
471*b321acabSVincenzo Maffione 
472*b321acabSVincenzo Maffione 	csb_atok_base = priv->np_csb_atok_base;
473*b321acabSVincenzo Maffione 	csb_ktoa_base = priv->np_csb_ktoa_base;
474*b321acabSVincenzo Maffione 
475*b321acabSVincenzo Maffione 	/* Make sure that no kloop is currently running. */
476*b321acabSVincenzo Maffione 	if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
477*b321acabSVincenzo Maffione 		err = EBUSY;
478*b321acabSVincenzo Maffione 	}
479*b321acabSVincenzo Maffione 	priv->np_kloop_state |= NM_SYNC_KLOOP_RUNNING;
480*b321acabSVincenzo Maffione 	NMG_UNLOCK();
481*b321acabSVincenzo Maffione 	if (err) {
482*b321acabSVincenzo Maffione 		return err;
483*b321acabSVincenzo Maffione 	}
484*b321acabSVincenzo Maffione 
485*b321acabSVincenzo Maffione 	num_rx_rings = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX];
486*b321acabSVincenzo Maffione 	num_tx_rings = priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
487*b321acabSVincenzo Maffione 	num_rings = num_tx_rings + num_rx_rings;
488*b321acabSVincenzo Maffione 
489*b321acabSVincenzo Maffione 	/* Validate notification options. */
490*b321acabSVincenzo Maffione 	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
491*b321acabSVincenzo Maffione 				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
492*b321acabSVincenzo Maffione 	if (opt != NULL) {
493*b321acabSVincenzo Maffione 		err = nmreq_checkduplicate(opt);
494*b321acabSVincenzo Maffione 		if (err) {
495*b321acabSVincenzo Maffione 			opt->nro_status = err;
496*b321acabSVincenzo Maffione 			goto out;
497*b321acabSVincenzo Maffione 		}
498*b321acabSVincenzo Maffione 		if (opt->nro_size != sizeof(*eventfds_opt) +
499*b321acabSVincenzo Maffione 			sizeof(eventfds_opt->eventfds[0]) * num_rings) {
500*b321acabSVincenzo Maffione 			/* Option size not consistent with the number of
501*b321acabSVincenzo Maffione 			 * entries. */
502*b321acabSVincenzo Maffione 			opt->nro_status = err = EINVAL;
503*b321acabSVincenzo Maffione 			goto out;
504*b321acabSVincenzo Maffione 		}
505*b321acabSVincenzo Maffione #ifdef SYNC_KLOOP_POLL
506*b321acabSVincenzo Maffione 		eventfds_opt = (struct nmreq_opt_sync_kloop_eventfds *)opt;
507*b321acabSVincenzo Maffione 		opt->nro_status = 0;
508*b321acabSVincenzo Maffione 		/* We need 2 poll entries for TX and RX notifications coming
509*b321acabSVincenzo Maffione 		 * from the netmap adapter, plus one entries per ring for the
510*b321acabSVincenzo Maffione 		 * notifications coming from the application. */
511*b321acabSVincenzo Maffione 		poll_ctx = nm_os_malloc(sizeof(*poll_ctx) +
512*b321acabSVincenzo Maffione 				(2 + num_rings) * sizeof(poll_ctx->entries[0]));
513*b321acabSVincenzo Maffione 		init_poll_funcptr(&poll_ctx->wait_table,
514*b321acabSVincenzo Maffione 					sync_kloop_poll_table_queue_proc);
515*b321acabSVincenzo Maffione 		poll_ctx->num_entries = 2 + num_rings;
516*b321acabSVincenzo Maffione 		poll_ctx->next_entry = 0;
517*b321acabSVincenzo Maffione 		/* Poll for notifications coming from the applications through
518*b321acabSVincenzo Maffione 		 * eventfds . */
519*b321acabSVincenzo Maffione 		for (i = 0; i < num_rings; i++) {
520*b321acabSVincenzo Maffione 			struct eventfd_ctx *irq;
521*b321acabSVincenzo Maffione 			struct file *filp;
522*b321acabSVincenzo Maffione 			unsigned long mask;
523*b321acabSVincenzo Maffione 
524*b321acabSVincenzo Maffione 			filp = eventfd_fget(eventfds_opt->eventfds[i].ioeventfd);
525*b321acabSVincenzo Maffione 			if (IS_ERR(filp)) {
526*b321acabSVincenzo Maffione 				err = PTR_ERR(filp);
527*b321acabSVincenzo Maffione 				goto out;
528*b321acabSVincenzo Maffione 			}
529*b321acabSVincenzo Maffione 			mask = filp->f_op->poll(filp, &poll_ctx->wait_table);
530*b321acabSVincenzo Maffione 			if (mask & POLLERR) {
531*b321acabSVincenzo Maffione 				err = EINVAL;
532*b321acabSVincenzo Maffione 				goto out;
533*b321acabSVincenzo Maffione 			}
534*b321acabSVincenzo Maffione 
535*b321acabSVincenzo Maffione 			filp = eventfd_fget(eventfds_opt->eventfds[i].irqfd);
536*b321acabSVincenzo Maffione 			if (IS_ERR(filp)) {
537*b321acabSVincenzo Maffione 				err = PTR_ERR(filp);
538*b321acabSVincenzo Maffione 				goto out;
539*b321acabSVincenzo Maffione 			}
540*b321acabSVincenzo Maffione 			poll_ctx->entries[i].irq_filp = filp;
541*b321acabSVincenzo Maffione 			irq = eventfd_ctx_fileget(filp);
542*b321acabSVincenzo Maffione 			if (IS_ERR(irq)) {
543*b321acabSVincenzo Maffione 				err = PTR_ERR(irq);
544*b321acabSVincenzo Maffione 				goto out;
545*b321acabSVincenzo Maffione 			}
546*b321acabSVincenzo Maffione 			poll_ctx->entries[i].irq_ctx = irq;
547*b321acabSVincenzo Maffione 		}
548*b321acabSVincenzo Maffione 		/* Poll for notifications coming from the netmap rings bound to
549*b321acabSVincenzo Maffione 		 * this file descriptor. */
550*b321acabSVincenzo Maffione 		{
551*b321acabSVincenzo Maffione 			NM_SELINFO_T *si[NR_TXRX];
552*b321acabSVincenzo Maffione 
553*b321acabSVincenzo Maffione 			NMG_LOCK();
554*b321acabSVincenzo Maffione 			si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
555*b321acabSVincenzo Maffione 				&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
556*b321acabSVincenzo Maffione 			si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
557*b321acabSVincenzo Maffione 				&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
558*b321acabSVincenzo Maffione 			NMG_UNLOCK();
559*b321acabSVincenzo Maffione 			poll_wait(priv->np_filp, si[NR_RX], &poll_ctx->wait_table);
560*b321acabSVincenzo Maffione 			poll_wait(priv->np_filp, si[NR_TX], &poll_ctx->wait_table);
561*b321acabSVincenzo Maffione 		}
562*b321acabSVincenzo Maffione #else   /* SYNC_KLOOP_POLL */
563*b321acabSVincenzo Maffione 		opt->nro_status = EOPNOTSUPP;
564*b321acabSVincenzo Maffione 		goto out;
565*b321acabSVincenzo Maffione #endif  /* SYNC_KLOOP_POLL */
566*b321acabSVincenzo Maffione 	}
567*b321acabSVincenzo Maffione 
568*b321acabSVincenzo Maffione 	/* Main loop. */
569*b321acabSVincenzo Maffione 	for (;;) {
570*b321acabSVincenzo Maffione 		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
571*b321acabSVincenzo Maffione 			break;
572*b321acabSVincenzo Maffione 		}
573*b321acabSVincenzo Maffione 
574*b321acabSVincenzo Maffione #ifdef SYNC_KLOOP_POLL
575*b321acabSVincenzo Maffione 		if (poll_ctx)
576*b321acabSVincenzo Maffione 			__set_current_state(TASK_INTERRUPTIBLE);
577*b321acabSVincenzo Maffione #endif  /* SYNC_KLOOP_POLL */
578*b321acabSVincenzo Maffione 
579*b321acabSVincenzo Maffione 		/* Process all the TX rings bound to this file descriptor. */
580*b321acabSVincenzo Maffione 		for (i = 0; i < num_tx_rings; i++) {
581*b321acabSVincenzo Maffione 			struct sync_kloop_ring_args a = {
582*b321acabSVincenzo Maffione 				.kring = NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]],
583*b321acabSVincenzo Maffione 				.csb_atok = csb_atok_base + i,
584*b321acabSVincenzo Maffione 				.csb_ktoa = csb_ktoa_base + i,
585*b321acabSVincenzo Maffione 			};
586*b321acabSVincenzo Maffione 
587*b321acabSVincenzo Maffione #ifdef SYNC_KLOOP_POLL
588*b321acabSVincenzo Maffione 			if (poll_ctx)
589*b321acabSVincenzo Maffione 				a.irq_ctx = poll_ctx->entries[i].irq_ctx;
590*b321acabSVincenzo Maffione #endif /* SYNC_KLOOP_POLL */
591*b321acabSVincenzo Maffione 			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
592*b321acabSVincenzo Maffione 				continue;
593*b321acabSVincenzo Maffione 			}
594*b321acabSVincenzo Maffione 			netmap_sync_kloop_tx_ring(&a);
595*b321acabSVincenzo Maffione 			nm_kr_put(a.kring);
596*b321acabSVincenzo Maffione 		}
597*b321acabSVincenzo Maffione 
598*b321acabSVincenzo Maffione 		/* Process all the RX rings bound to this file descriptor. */
599*b321acabSVincenzo Maffione 		for (i = 0; i < num_rx_rings; i++) {
600*b321acabSVincenzo Maffione 			struct sync_kloop_ring_args a = {
601*b321acabSVincenzo Maffione 				.kring = NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]],
602*b321acabSVincenzo Maffione 				.csb_atok = csb_atok_base + num_tx_rings + i,
603*b321acabSVincenzo Maffione 				.csb_ktoa = csb_ktoa_base + num_tx_rings + i,
604*b321acabSVincenzo Maffione 			};
605*b321acabSVincenzo Maffione 
606*b321acabSVincenzo Maffione #ifdef SYNC_KLOOP_POLL
607*b321acabSVincenzo Maffione 			if (poll_ctx)
608*b321acabSVincenzo Maffione 				a.irq_ctx = poll_ctx->entries[num_tx_rings + i].irq_ctx;
609*b321acabSVincenzo Maffione #endif /* SYNC_KLOOP_POLL */
610*b321acabSVincenzo Maffione 
611*b321acabSVincenzo Maffione 			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
612*b321acabSVincenzo Maffione 				continue;
613*b321acabSVincenzo Maffione 			}
614*b321acabSVincenzo Maffione 			netmap_sync_kloop_rx_ring(&a);
615*b321acabSVincenzo Maffione 			nm_kr_put(a.kring);
616*b321acabSVincenzo Maffione 		}
617*b321acabSVincenzo Maffione 
618*b321acabSVincenzo Maffione #ifdef SYNC_KLOOP_POLL
619*b321acabSVincenzo Maffione 		if (poll_ctx) {
620*b321acabSVincenzo Maffione 			/* If a poll context is present, yield to the scheduler
621*b321acabSVincenzo Maffione 			 * waiting for a notification to come either from
622*b321acabSVincenzo Maffione 			 * netmap or the application. */
623*b321acabSVincenzo Maffione 			schedule_timeout_interruptible(msecs_to_jiffies(1000));
624*b321acabSVincenzo Maffione 		} else
625*b321acabSVincenzo Maffione #endif /* SYNC_KLOOP_POLL */
626*b321acabSVincenzo Maffione 		{
627*b321acabSVincenzo Maffione 			/* Default synchronization method: sleep for a while. */
628*b321acabSVincenzo Maffione 			usleep_range(sleep_us, sleep_us);
629*b321acabSVincenzo Maffione 		}
630*b321acabSVincenzo Maffione 	}
631*b321acabSVincenzo Maffione out:
632*b321acabSVincenzo Maffione #ifdef SYNC_KLOOP_POLL
633*b321acabSVincenzo Maffione 	if (poll_ctx) {
634*b321acabSVincenzo Maffione 		/* Stop polling from netmap and the eventfds, and deallocate
635*b321acabSVincenzo Maffione 		 * the poll context. */
636*b321acabSVincenzo Maffione 		__set_current_state(TASK_RUNNING);
637*b321acabSVincenzo Maffione 		for (i = 0; i < poll_ctx->next_entry; i++) {
638*b321acabSVincenzo Maffione 			struct sync_kloop_poll_entry *entry =
639*b321acabSVincenzo Maffione 						poll_ctx->entries + i;
640*b321acabSVincenzo Maffione 
641*b321acabSVincenzo Maffione 			if (entry->wqh)
642*b321acabSVincenzo Maffione 				remove_wait_queue(entry->wqh, &entry->wait);
643*b321acabSVincenzo Maffione 			/* We did not get a reference to the eventfds, but
644*b321acabSVincenzo Maffione 			 * don't do that on netmap file descriptors (since
645*b321acabSVincenzo Maffione 			 * a reference was not taken. */
646*b321acabSVincenzo Maffione 			if (entry->filp && entry->filp != priv->np_filp)
647*b321acabSVincenzo Maffione 				fput(entry->filp);
648*b321acabSVincenzo Maffione 			if (entry->irq_ctx)
649*b321acabSVincenzo Maffione 				eventfd_ctx_put(entry->irq_ctx);
650*b321acabSVincenzo Maffione 			if (entry->irq_filp)
651*b321acabSVincenzo Maffione 				fput(entry->irq_filp);
652*b321acabSVincenzo Maffione 		}
653*b321acabSVincenzo Maffione 		nm_os_free(poll_ctx);
654*b321acabSVincenzo Maffione 		poll_ctx = NULL;
655*b321acabSVincenzo Maffione 	}
656*b321acabSVincenzo Maffione #endif /* SYNC_KLOOP_POLL */
657*b321acabSVincenzo Maffione 
658*b321acabSVincenzo Maffione 	/* Reset the kloop state. */
659*b321acabSVincenzo Maffione 	NMG_LOCK();
660*b321acabSVincenzo Maffione 	priv->np_kloop_state = 0;
661*b321acabSVincenzo Maffione 	NMG_UNLOCK();
662*b321acabSVincenzo Maffione 
663*b321acabSVincenzo Maffione 	return err;
664*b321acabSVincenzo Maffione }
665*b321acabSVincenzo Maffione 
666*b321acabSVincenzo Maffione int
667*b321acabSVincenzo Maffione netmap_sync_kloop_stop(struct netmap_priv_d *priv)
668*b321acabSVincenzo Maffione {
669*b321acabSVincenzo Maffione 	bool running = true;
670*b321acabSVincenzo Maffione 	int err = 0;
671*b321acabSVincenzo Maffione 
672*b321acabSVincenzo Maffione 	NMG_LOCK();
673*b321acabSVincenzo Maffione 	priv->np_kloop_state |= NM_SYNC_KLOOP_STOPPING;
674*b321acabSVincenzo Maffione 	NMG_UNLOCK();
675*b321acabSVincenzo Maffione 	while (running) {
676*b321acabSVincenzo Maffione 		usleep_range(1000, 1500);
677*b321acabSVincenzo Maffione 		NMG_LOCK();
678*b321acabSVincenzo Maffione 		running = (NM_ACCESS_ONCE(priv->np_kloop_state)
679*b321acabSVincenzo Maffione 				& NM_SYNC_KLOOP_RUNNING);
680*b321acabSVincenzo Maffione 		NMG_UNLOCK();
681*b321acabSVincenzo Maffione 	}
682*b321acabSVincenzo Maffione 
683*b321acabSVincenzo Maffione 	return err;
684*b321acabSVincenzo Maffione }
685*b321acabSVincenzo Maffione 
686*b321acabSVincenzo Maffione #ifdef WITH_PTNETMAP
687*b321acabSVincenzo Maffione /*
688*b321acabSVincenzo Maffione  * Guest ptnetmap txsync()/rxsync() routines, used in ptnet device drivers.
689*b321acabSVincenzo Maffione  * These routines are reused across the different operating systems supported
690*b321acabSVincenzo Maffione  * by netmap.
691*b321acabSVincenzo Maffione  */
692*b321acabSVincenzo Maffione 
693*b321acabSVincenzo Maffione /*
694*b321acabSVincenzo Maffione  * Reconcile host and guest views of the transmit ring.
695*b321acabSVincenzo Maffione  *
696*b321acabSVincenzo Maffione  * Guest user wants to transmit packets up to the one before ring->head,
697*b321acabSVincenzo Maffione  * and guest kernel knows tx_ring->hwcur is the first packet unsent
698*b321acabSVincenzo Maffione  * by the host kernel.
699*b321acabSVincenzo Maffione  *
700*b321acabSVincenzo Maffione  * We push out as many packets as possible, and possibly
701*b321acabSVincenzo Maffione  * reclaim buffers from previously completed transmission.
702*b321acabSVincenzo Maffione  *
703*b321acabSVincenzo Maffione  * Notifications from the host are enabled only if the user guest would
704*b321acabSVincenzo Maffione  * block (no space in the ring).
705*b321acabSVincenzo Maffione  */
706*b321acabSVincenzo Maffione bool
707*b321acabSVincenzo Maffione netmap_pt_guest_txsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
708*b321acabSVincenzo Maffione 			struct netmap_kring *kring, int flags)
709*b321acabSVincenzo Maffione {
710*b321acabSVincenzo Maffione 	bool notify = false;
711*b321acabSVincenzo Maffione 
712*b321acabSVincenzo Maffione 	/* Disable notifications */
713*b321acabSVincenzo Maffione 	atok->appl_need_kick = 0;
714*b321acabSVincenzo Maffione 
715*b321acabSVincenzo Maffione 	/*
716*b321acabSVincenzo Maffione 	 * First part: tell the host (updating the CSB) to process the new
717*b321acabSVincenzo Maffione 	 * packets.
718*b321acabSVincenzo Maffione 	 */
719*b321acabSVincenzo Maffione 	kring->nr_hwcur = ktoa->hwcur;
720*b321acabSVincenzo Maffione 	ptnetmap_guest_write_kring_csb(atok, kring->rcur, kring->rhead);
721*b321acabSVincenzo Maffione 
722*b321acabSVincenzo Maffione         /* Ask for a kick from a guest to the host if needed. */
723*b321acabSVincenzo Maffione 	if (((kring->rhead != kring->nr_hwcur || nm_kr_txempty(kring))
724*b321acabSVincenzo Maffione 		&& NM_ACCESS_ONCE(ktoa->kern_need_kick)) ||
725*b321acabSVincenzo Maffione 			(flags & NAF_FORCE_RECLAIM)) {
726*b321acabSVincenzo Maffione 		atok->sync_flags = flags;
727*b321acabSVincenzo Maffione 		notify = true;
728*b321acabSVincenzo Maffione 	}
729*b321acabSVincenzo Maffione 
730*b321acabSVincenzo Maffione 	/*
731*b321acabSVincenzo Maffione 	 * Second part: reclaim buffers for completed transmissions.
732*b321acabSVincenzo Maffione 	 */
733*b321acabSVincenzo Maffione 	if (nm_kr_txempty(kring) || (flags & NAF_FORCE_RECLAIM)) {
734*b321acabSVincenzo Maffione                 ptnetmap_guest_read_kring_csb(ktoa, kring);
735*b321acabSVincenzo Maffione 	}
736*b321acabSVincenzo Maffione 
737*b321acabSVincenzo Maffione         /*
738*b321acabSVincenzo Maffione          * No more room in the ring for new transmissions. The user thread will
739*b321acabSVincenzo Maffione 	 * go to sleep and we need to be notified by the host when more free
740*b321acabSVincenzo Maffione 	 * space is available.
741*b321acabSVincenzo Maffione          */
742*b321acabSVincenzo Maffione 	if (nm_kr_txempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
743*b321acabSVincenzo Maffione 		/* Reenable notifications. */
744*b321acabSVincenzo Maffione 		atok->appl_need_kick = 1;
745*b321acabSVincenzo Maffione                 /* Double check */
746*b321acabSVincenzo Maffione                 ptnetmap_guest_read_kring_csb(ktoa, kring);
747*b321acabSVincenzo Maffione                 /* If there is new free space, disable notifications */
748*b321acabSVincenzo Maffione 		if (unlikely(!nm_kr_txempty(kring))) {
749*b321acabSVincenzo Maffione 			atok->appl_need_kick = 0;
750*b321acabSVincenzo Maffione 		}
751*b321acabSVincenzo Maffione 	}
752*b321acabSVincenzo Maffione 
753*b321acabSVincenzo Maffione 	nm_prdis(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
754*b321acabSVincenzo Maffione 		kring->name, atok->head, atok->cur, ktoa->hwtail,
755*b321acabSVincenzo Maffione 		kring->rhead, kring->rcur, kring->nr_hwtail);
756*b321acabSVincenzo Maffione 
757*b321acabSVincenzo Maffione 	return notify;
758*b321acabSVincenzo Maffione }
759*b321acabSVincenzo Maffione 
760*b321acabSVincenzo Maffione /*
761*b321acabSVincenzo Maffione  * Reconcile host and guest view of the receive ring.
762*b321acabSVincenzo Maffione  *
763*b321acabSVincenzo Maffione  * Update hwcur/hwtail from host (reading from CSB).
764*b321acabSVincenzo Maffione  *
765*b321acabSVincenzo Maffione  * If guest user has released buffers up to the one before ring->head, we
766*b321acabSVincenzo Maffione  * also give them to the host.
767*b321acabSVincenzo Maffione  *
768*b321acabSVincenzo Maffione  * Notifications from the host are enabled only if the user guest would
769*b321acabSVincenzo Maffione  * block (no more completed slots in the ring).
770*b321acabSVincenzo Maffione  */
771*b321acabSVincenzo Maffione bool
772*b321acabSVincenzo Maffione netmap_pt_guest_rxsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
773*b321acabSVincenzo Maffione 			struct netmap_kring *kring, int flags)
774*b321acabSVincenzo Maffione {
775*b321acabSVincenzo Maffione 	bool notify = false;
776*b321acabSVincenzo Maffione 
777*b321acabSVincenzo Maffione         /* Disable notifications */
778*b321acabSVincenzo Maffione 	atok->appl_need_kick = 0;
779*b321acabSVincenzo Maffione 
780*b321acabSVincenzo Maffione 	/*
781*b321acabSVincenzo Maffione 	 * First part: import newly received packets, by updating the kring
782*b321acabSVincenzo Maffione 	 * hwtail to the hwtail known from the host (read from the CSB).
783*b321acabSVincenzo Maffione 	 * This also updates the kring hwcur.
784*b321acabSVincenzo Maffione 	 */
785*b321acabSVincenzo Maffione         ptnetmap_guest_read_kring_csb(ktoa, kring);
786*b321acabSVincenzo Maffione 	kring->nr_kflags &= ~NKR_PENDINTR;
787*b321acabSVincenzo Maffione 
788*b321acabSVincenzo Maffione 	/*
789*b321acabSVincenzo Maffione 	 * Second part: tell the host about the slots that guest user has
790*b321acabSVincenzo Maffione 	 * released, by updating cur and head in the CSB.
791*b321acabSVincenzo Maffione 	 */
792*b321acabSVincenzo Maffione 	if (kring->rhead != kring->nr_hwcur) {
793*b321acabSVincenzo Maffione 		ptnetmap_guest_write_kring_csb(atok, kring->rcur,
794*b321acabSVincenzo Maffione 					       kring->rhead);
795*b321acabSVincenzo Maffione                 /* Ask for a kick from the guest to the host if needed. */
796*b321acabSVincenzo Maffione 		if (NM_ACCESS_ONCE(ktoa->kern_need_kick)) {
797*b321acabSVincenzo Maffione 			atok->sync_flags = flags;
798*b321acabSVincenzo Maffione 			notify = true;
799*b321acabSVincenzo Maffione 		}
800*b321acabSVincenzo Maffione 	}
801*b321acabSVincenzo Maffione 
802*b321acabSVincenzo Maffione         /*
803*b321acabSVincenzo Maffione          * No more completed RX slots. The user thread will go to sleep and
804*b321acabSVincenzo Maffione 	 * we need to be notified by the host when more RX slots have been
805*b321acabSVincenzo Maffione 	 * completed.
806*b321acabSVincenzo Maffione          */
807*b321acabSVincenzo Maffione 	if (nm_kr_rxempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
808*b321acabSVincenzo Maffione 		/* Reenable notifications. */
809*b321acabSVincenzo Maffione                 atok->appl_need_kick = 1;
810*b321acabSVincenzo Maffione                 /* Double check */
811*b321acabSVincenzo Maffione                 ptnetmap_guest_read_kring_csb(ktoa, kring);
812*b321acabSVincenzo Maffione                 /* If there are new slots, disable notifications. */
813*b321acabSVincenzo Maffione 		if (!nm_kr_rxempty(kring)) {
814*b321acabSVincenzo Maffione                         atok->appl_need_kick = 0;
815*b321acabSVincenzo Maffione                 }
816*b321acabSVincenzo Maffione         }
817*b321acabSVincenzo Maffione 
818*b321acabSVincenzo Maffione 	nm_prdis(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
819*b321acabSVincenzo Maffione 		kring->name, atok->head, atok->cur, ktoa->hwtail,
820*b321acabSVincenzo Maffione 		kring->rhead, kring->rcur, kring->nr_hwtail);
821*b321acabSVincenzo Maffione 
822*b321acabSVincenzo Maffione 	return notify;
823*b321acabSVincenzo Maffione }
824*b321acabSVincenzo Maffione 
825*b321acabSVincenzo Maffione /*
826*b321acabSVincenzo Maffione  * Callbacks for ptnet drivers: nm_krings_create, nm_krings_delete, nm_dtor.
827*b321acabSVincenzo Maffione  */
828*b321acabSVincenzo Maffione int
829*b321acabSVincenzo Maffione ptnet_nm_krings_create(struct netmap_adapter *na)
830*b321acabSVincenzo Maffione {
831*b321acabSVincenzo Maffione 	struct netmap_pt_guest_adapter *ptna =
832*b321acabSVincenzo Maffione 			(struct netmap_pt_guest_adapter *)na; /* Upcast. */
833*b321acabSVincenzo Maffione 	struct netmap_adapter *na_nm = &ptna->hwup.up;
834*b321acabSVincenzo Maffione 	struct netmap_adapter *na_dr = &ptna->dr.up;
835*b321acabSVincenzo Maffione 	int ret;
836*b321acabSVincenzo Maffione 
837*b321acabSVincenzo Maffione 	if (ptna->backend_users) {
838*b321acabSVincenzo Maffione 		return 0;
839*b321acabSVincenzo Maffione 	}
840*b321acabSVincenzo Maffione 
841*b321acabSVincenzo Maffione 	/* Create krings on the public netmap adapter. */
842*b321acabSVincenzo Maffione 	ret = netmap_hw_krings_create(na_nm);
843*b321acabSVincenzo Maffione 	if (ret) {
844*b321acabSVincenzo Maffione 		return ret;
845*b321acabSVincenzo Maffione 	}
846*b321acabSVincenzo Maffione 
847*b321acabSVincenzo Maffione 	/* Copy krings into the netmap adapter private to the driver. */
848*b321acabSVincenzo Maffione 	na_dr->tx_rings = na_nm->tx_rings;
849*b321acabSVincenzo Maffione 	na_dr->rx_rings = na_nm->rx_rings;
850*b321acabSVincenzo Maffione 
851*b321acabSVincenzo Maffione 	return 0;
852*b321acabSVincenzo Maffione }
853*b321acabSVincenzo Maffione 
854*b321acabSVincenzo Maffione void
855*b321acabSVincenzo Maffione ptnet_nm_krings_delete(struct netmap_adapter *na)
856*b321acabSVincenzo Maffione {
857*b321acabSVincenzo Maffione 	struct netmap_pt_guest_adapter *ptna =
858*b321acabSVincenzo Maffione 			(struct netmap_pt_guest_adapter *)na; /* Upcast. */
859*b321acabSVincenzo Maffione 	struct netmap_adapter *na_nm = &ptna->hwup.up;
860*b321acabSVincenzo Maffione 	struct netmap_adapter *na_dr = &ptna->dr.up;
861*b321acabSVincenzo Maffione 
862*b321acabSVincenzo Maffione 	if (ptna->backend_users) {
863*b321acabSVincenzo Maffione 		return;
864*b321acabSVincenzo Maffione 	}
865*b321acabSVincenzo Maffione 
866*b321acabSVincenzo Maffione 	na_dr->tx_rings = NULL;
867*b321acabSVincenzo Maffione 	na_dr->rx_rings = NULL;
868*b321acabSVincenzo Maffione 
869*b321acabSVincenzo Maffione 	netmap_hw_krings_delete(na_nm);
870*b321acabSVincenzo Maffione }
871*b321acabSVincenzo Maffione 
872*b321acabSVincenzo Maffione void
873*b321acabSVincenzo Maffione ptnet_nm_dtor(struct netmap_adapter *na)
874*b321acabSVincenzo Maffione {
875*b321acabSVincenzo Maffione 	struct netmap_pt_guest_adapter *ptna =
876*b321acabSVincenzo Maffione 			(struct netmap_pt_guest_adapter *)na;
877*b321acabSVincenzo Maffione 
878*b321acabSVincenzo Maffione 	netmap_mem_put(ptna->dr.up.nm_mem);
879*b321acabSVincenzo Maffione 	memset(&ptna->dr, 0, sizeof(ptna->dr));
880*b321acabSVincenzo Maffione 	netmap_mem_pt_guest_ifp_del(na->nm_mem, na->ifp);
881*b321acabSVincenzo Maffione }
882*b321acabSVincenzo Maffione 
883*b321acabSVincenzo Maffione int
884*b321acabSVincenzo Maffione netmap_pt_guest_attach(struct netmap_adapter *arg,
885*b321acabSVincenzo Maffione 		       unsigned int nifp_offset, unsigned int memid)
886*b321acabSVincenzo Maffione {
887*b321acabSVincenzo Maffione 	struct netmap_pt_guest_adapter *ptna;
888*b321acabSVincenzo Maffione 	struct ifnet *ifp = arg ? arg->ifp : NULL;
889*b321acabSVincenzo Maffione 	int error;
890*b321acabSVincenzo Maffione 
891*b321acabSVincenzo Maffione 	/* get allocator */
892*b321acabSVincenzo Maffione 	arg->nm_mem = netmap_mem_pt_guest_new(ifp, nifp_offset, memid);
893*b321acabSVincenzo Maffione 	if (arg->nm_mem == NULL)
894*b321acabSVincenzo Maffione 		return ENOMEM;
895*b321acabSVincenzo Maffione 	arg->na_flags |= NAF_MEM_OWNER;
896*b321acabSVincenzo Maffione 	error = netmap_attach_ext(arg, sizeof(struct netmap_pt_guest_adapter), 1);
897*b321acabSVincenzo Maffione 	if (error)
898*b321acabSVincenzo Maffione 		return error;
899*b321acabSVincenzo Maffione 
900*b321acabSVincenzo Maffione 	/* get the netmap_pt_guest_adapter */
901*b321acabSVincenzo Maffione 	ptna = (struct netmap_pt_guest_adapter *) NA(ifp);
902*b321acabSVincenzo Maffione 
903*b321acabSVincenzo Maffione 	/* Initialize a separate pass-through netmap adapter that is going to
904*b321acabSVincenzo Maffione 	 * be used by the ptnet driver only, and so never exposed to netmap
905*b321acabSVincenzo Maffione          * applications. We only need a subset of the available fields. */
906*b321acabSVincenzo Maffione 	memset(&ptna->dr, 0, sizeof(ptna->dr));
907*b321acabSVincenzo Maffione 	ptna->dr.up.ifp = ifp;
908*b321acabSVincenzo Maffione 	ptna->dr.up.nm_mem = netmap_mem_get(ptna->hwup.up.nm_mem);
909*b321acabSVincenzo Maffione         ptna->dr.up.nm_config = ptna->hwup.up.nm_config;
910*b321acabSVincenzo Maffione 
911*b321acabSVincenzo Maffione 	ptna->backend_users = 0;
912*b321acabSVincenzo Maffione 
913*b321acabSVincenzo Maffione 	return 0;
914*b321acabSVincenzo Maffione }
915*b321acabSVincenzo Maffione 
916*b321acabSVincenzo Maffione #endif /* WITH_PTNETMAP */
917