1227614Sluigi/*
2262151Sluigi * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
3227614Sluigi *
4227614Sluigi * Redistribution and use in source and binary forms, with or without
5227614Sluigi * modification, are permitted provided that the following conditions
6227614Sluigi * are met:
7227614Sluigi * 1. Redistributions of source code must retain the above copyright
8227614Sluigi *    notice, this list of conditions and the following disclaimer.
9227614Sluigi * 2. Redistributions in binary form must reproduce the above copyright
10227614Sluigi *    notice, this list of conditions and the following disclaimer in the
11227614Sluigi *    documentation and/or other materials provided with the distribution.
12227614Sluigi *
13227614Sluigi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14227614Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15227614Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16227614Sluigi * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17227614Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18227614Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19227614Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20227614Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21227614Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22227614Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23227614Sluigi * SUCH DAMAGE.
24227614Sluigi */
25227614Sluigi
26232238Sluigi
27227614Sluigi/*
28227614Sluigi * $FreeBSD$
29227614Sluigi *
30262151Sluigi * netmap support for: lem
31228276Sluigi *
32232238Sluigi * For details on netmap support please see ixgbe_netmap.h
33227614Sluigi */
34227614Sluigi
35262151Sluigi
36227614Sluigi#include <net/netmap.h>
37227614Sluigi#include <sys/selinfo.h>
38227614Sluigi#include <vm/vm.h>
39227614Sluigi#include <vm/pmap.h>    /* vtophys ? */
40227614Sluigi#include <dev/netmap/netmap_kern.h>
41227614Sluigi
42270252Sluigiextern int netmap_adaptive_io;
43227614Sluigi
44227614Sluigi/*
45262151Sluigi * Register/unregister. We are already under netmap lock.
46227614Sluigi */
47227614Sluigistatic int
48262151Sluigilem_netmap_reg(struct netmap_adapter *na, int onoff)
49228276Sluigi{
50262151Sluigi	struct ifnet *ifp = na->ifp;
51228276Sluigi	struct adapter *adapter = ifp->if_softc;
52228276Sluigi
53262151Sluigi	EM_CORE_LOCK(adapter);
54228276Sluigi
55228276Sluigi	lem_disable_intr(adapter);
56228276Sluigi
57228276Sluigi	/* Tell the stack that the interface is no longer active */
58228276Sluigi	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
59228276Sluigi
60228276Sluigi#ifndef EM_LEGACY_IRQ // XXX do we need this ?
61228276Sluigi	taskqueue_block(adapter->tq);
62228276Sluigi	taskqueue_drain(adapter->tq, &adapter->rxtx_task);
63228276Sluigi	taskqueue_drain(adapter->tq, &adapter->link_task);
64228276Sluigi#endif /* !EM_LEGCY_IRQ */
65262151Sluigi
66262151Sluigi	/* enable or disable flags and callbacks in na and ifp */
67228276Sluigi	if (onoff) {
68262151Sluigi		nm_set_native_flags(na);
69228276Sluigi	} else {
70262151Sluigi		nm_clear_native_flags(na);
71228276Sluigi	}
72262151Sluigi	lem_init_locked(adapter);	/* also enable intr */
73228276Sluigi
74228276Sluigi#ifndef EM_LEGACY_IRQ
75228276Sluigi	taskqueue_unblock(adapter->tq); // XXX do we need this ?
76228276Sluigi#endif /* !EM_LEGCY_IRQ */
77228276Sluigi
78262151Sluigi	EM_CORE_UNLOCK(adapter);
79262151Sluigi
80262151Sluigi	return (ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1);
81228276Sluigi}
82228276Sluigi
83228276Sluigi
84228276Sluigi/*
85232238Sluigi * Reconcile kernel and user view of the transmit ring.
86228276Sluigi */
87228276Sluigistatic int
88270252Sluigilem_netmap_txsync(struct netmap_kring *kring, int flags)
89227614Sluigi{
90270252Sluigi	struct netmap_adapter *na = kring->na;
91262151Sluigi	struct ifnet *ifp = na->ifp;
92227614Sluigi	struct netmap_ring *ring = kring->ring;
93262151Sluigi	u_int nm_i;	/* index into the netmap ring */
94262151Sluigi	u_int nic_i;	/* index into the NIC ring */
95262151Sluigi	u_int const lim = kring->nkr_num_slots - 1;
96262151Sluigi	u_int const head = kring->rhead;
97227614Sluigi	/* generate an interrupt approximately every half ring */
98262151Sluigi	u_int report_frequency = kring->nkr_num_slots >> 1;
99227614Sluigi
100262151Sluigi	/* device-specific */
101262151Sluigi	struct adapter *adapter = ifp->if_softc;
102270252Sluigi#ifdef NIC_PARAVIRT
103270252Sluigi	struct paravirt_csb *csb = adapter->csb;
104270252Sluigi	uint64_t *csbd = (uint64_t *)(csb + 1);
105270252Sluigi#endif /* NIC_PARAVIRT */
106227614Sluigi
107227614Sluigi	bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map,
108227614Sluigi			BUS_DMASYNC_POSTREAD);
109262151Sluigi
110232238Sluigi	/*
111262151Sluigi	 * First part: process new packets to send.
112231778Sluigi	 */
113262151Sluigi
114262151Sluigi	nm_i = kring->nr_hwcur;
115262151Sluigi	if (nm_i != head) {	/* we have new packets to send */
116270252Sluigi#ifdef NIC_PARAVIRT
117270252Sluigi		int do_kick = 0;
118270252Sluigi		uint64_t t = 0; // timestamp
119270252Sluigi		int n = head - nm_i;
120270252Sluigi		if (n < 0)
121270252Sluigi			n += lim + 1;
122270252Sluigi		if (csb) {
123270252Sluigi			t = rdtsc(); /* last timestamp */
124270252Sluigi			csbd[16] += t - csbd[0]; /* total Wg */
125270252Sluigi			csbd[17] += n;		/* Wg count */
126270252Sluigi			csbd[0] = t;
127270252Sluigi		}
128270252Sluigi#endif /* NIC_PARAVIRT */
129262151Sluigi		nic_i = netmap_idx_k2n(kring, nm_i);
130262151Sluigi		while (nm_i != head) {
131262151Sluigi			struct netmap_slot *slot = &ring->slot[nm_i];
132262151Sluigi			u_int len = slot->len;
133231778Sluigi			uint64_t paddr;
134270252Sluigi			void *addr = PNMB(na, slot, &paddr);
135227614Sluigi
136262151Sluigi			/* device-specific */
137262151Sluigi			struct e1000_tx_desc *curr = &adapter->tx_desc_base[nic_i];
138262151Sluigi			struct em_buffer *txbuf = &adapter->tx_buffer_area[nic_i];
139262151Sluigi			int flags = (slot->flags & NS_REPORT ||
140262151Sluigi				nic_i == 0 || nic_i == report_frequency) ?
141262151Sluigi				E1000_TXD_CMD_RS : 0;
142227614Sluigi
143270252Sluigi			NM_CHECK_ADDR_LEN(na, addr, len);
144262151Sluigi
145227614Sluigi			if (slot->flags & NS_BUF_CHANGED) {
146228276Sluigi				/* buffer has changed, reload map */
147262151Sluigi				curr->buffer_addr = htole64(paddr);
148270252Sluigi				netmap_reload_map(na, adapter->txtag, txbuf->map, addr);
149227614Sluigi			}
150262151Sluigi			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
151262151Sluigi
152262151Sluigi			/* Fill the slot in the NIC ring. */
153232238Sluigi			curr->upper.data = 0;
154262151Sluigi			curr->lower.data = htole32(adapter->txd_cmd | len |
155232238Sluigi				(E1000_TXD_CMD_EOP | flags) );
156262151Sluigi			bus_dmamap_sync(adapter->txtag, txbuf->map,
157262151Sluigi				BUS_DMASYNC_PREWRITE);
158227614Sluigi
159262151Sluigi			nm_i = nm_next(nm_i, lim);
160262151Sluigi			nic_i = nm_next(nic_i, lim);
161270252Sluigi			// XXX might try an early kick
162227614Sluigi		}
163262151Sluigi		kring->nr_hwcur = head;
164227614Sluigi
165262151Sluigi		 /* synchronize the NIC ring */
166227614Sluigi		bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map,
167262151Sluigi			BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
168227614Sluigi
169270252Sluigi#ifdef NIC_PARAVIRT
170270252Sluigi		/* set unconditionally, then also kick if needed */
171270252Sluigi		if (csb) {
172270252Sluigi			t = rdtsc();
173270252Sluigi			if (csb->host_need_txkick == 2) {
174270252Sluigi				/* can compute an update of delta */
175270252Sluigi				int64_t delta = t - csbd[3];
176270252Sluigi				if (delta < 0)
177270252Sluigi					delta = -delta;
178270252Sluigi				if (csbd[8] == 0 || delta < csbd[8]) {
179270252Sluigi					csbd[8] = delta;
180270252Sluigi					csbd[9]++;
181270252Sluigi				}
182270252Sluigi				csbd[10]++;
183270252Sluigi			}
184270252Sluigi			csb->guest_tdt = nic_i;
185270252Sluigi			csbd[18] += t - csbd[0]; // total wp
186270252Sluigi			csbd[19] += n;
187270252Sluigi		}
188270252Sluigi		if (!csb || !csb->guest_csb_on || (csb->host_need_txkick & 1))
189270252Sluigi			do_kick = 1;
190270252Sluigi		if (do_kick)
191270252Sluigi#endif /* NIC_PARAVIRT */
192262151Sluigi		/* (re)start the tx unit up to slot nic_i (excluded) */
193262151Sluigi		E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), nic_i);
194270252Sluigi#ifdef NIC_PARAVIRT
195270252Sluigi		if (do_kick) {
196270252Sluigi			uint64_t t1 = rdtsc();
197270252Sluigi			csbd[20] += t1 - t; // total Np
198270252Sluigi			csbd[21]++;
199270252Sluigi		}
200270252Sluigi#endif /* NIC_PARAVIRT */
201227614Sluigi	}
202228276Sluigi
203262151Sluigi	/*
204262151Sluigi	 * Second part: reclaim buffers for completed transmissions.
205262151Sluigi	 */
206262151Sluigi	if (ticks != kring->last_reclaim || flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
207262151Sluigi		kring->last_reclaim = ticks;
208228276Sluigi		/* record completed transmissions using TDH */
209270252Sluigi#ifdef NIC_PARAVIRT
210270252Sluigi		/* host updates tdh unconditionally, and we have
211270252Sluigi		 * no side effects on reads, so we can read from there
212270252Sluigi		 * instead of exiting.
213270252Sluigi		 */
214270252Sluigi		if (csb) {
215270252Sluigi		    static int drain = 0, nodrain=0, good = 0, bad = 0, fail = 0;
216270252Sluigi		    u_int x = adapter->next_tx_to_clean;
217270252Sluigi		    csbd[19]++; // XXX count reclaims
218270252Sluigi		    nic_i = csb->host_tdh;
219270252Sluigi		    if (csb->guest_csb_on) {
220270252Sluigi			if (nic_i == x) {
221270252Sluigi			    bad++;
222270252Sluigi		    	    csbd[24]++; // failed reclaims
223270252Sluigi			    /* no progress, request kick and retry */
224270252Sluigi			    csb->guest_need_txkick = 1;
225270252Sluigi			    mb(); // XXX barrier
226270252Sluigi		    	    nic_i = csb->host_tdh;
227270252Sluigi			} else {
228270252Sluigi			    good++;
229270252Sluigi			}
230270252Sluigi			if (nic_i != x) {
231270252Sluigi			    csb->guest_need_txkick = 2;
232270252Sluigi			    if (nic_i == csb->guest_tdt)
233270252Sluigi				drain++;
234270252Sluigi			    else
235270252Sluigi				nodrain++;
236270252Sluigi#if 1
237270252Sluigi			if (netmap_adaptive_io) {
238270252Sluigi			    /* new mechanism: last half ring (or so)
239270252Sluigi			     * released one slot at a time.
240270252Sluigi			     * This effectively makes the system spin.
241270252Sluigi			     *
242270252Sluigi			     * Take next_to_clean + 1 as a reference.
243270252Sluigi			     * tdh must be ahead or equal
244270252Sluigi			     * On entry, the logical order is
245270252Sluigi			     *		x < tdh = nic_i
246270252Sluigi			     * We first push tdh up to avoid wraps.
247270252Sluigi			     * The limit is tdh-ll (half ring).
248270252Sluigi			     * if tdh-256 < x we report x;
249270252Sluigi			     * else we report tdh-256
250270252Sluigi			     */
251270252Sluigi			    u_int tdh = nic_i;
252270252Sluigi			    u_int ll = csbd[15];
253270252Sluigi			    u_int delta = lim/8;
254270252Sluigi			    if (netmap_adaptive_io == 2 || ll > delta)
255270252Sluigi				csbd[15] = ll = delta;
256270252Sluigi			    else if (netmap_adaptive_io == 1 && ll > 1) {
257270252Sluigi				csbd[15]--;
258270252Sluigi			    }
259270252Sluigi
260270252Sluigi			    if (nic_i >= kring->nkr_num_slots) {
261270252Sluigi				RD(5, "bad nic_i %d on input", nic_i);
262270252Sluigi			    }
263270252Sluigi			    x = nm_next(x, lim);
264270252Sluigi			    if (tdh < x)
265270252Sluigi				tdh += lim + 1;
266270252Sluigi			    if (tdh <= x + ll) {
267270252Sluigi				nic_i = x;
268270252Sluigi				csbd[25]++; //report n + 1;
269270252Sluigi			    } else {
270270252Sluigi				tdh = nic_i;
271270252Sluigi				if (tdh < ll)
272270252Sluigi				    tdh += lim + 1;
273270252Sluigi				nic_i = tdh - ll;
274270252Sluigi				csbd[26]++; // report tdh - ll
275270252Sluigi			    }
276270252Sluigi			}
277270252Sluigi#endif
278270252Sluigi			} else {
279270252Sluigi			    /* we stop, count whether we are idle or not */
280270252Sluigi			    int bh_active = csb->host_need_txkick & 2 ? 4 : 0;
281270252Sluigi			    csbd[27+ csb->host_need_txkick]++;
282270252Sluigi			    if (netmap_adaptive_io == 1) {
283270252Sluigi				if (bh_active && csbd[15] > 1)
284270252Sluigi				    csbd[15]--;
285270252Sluigi				else if (!bh_active && csbd[15] < lim/2)
286270252Sluigi				    csbd[15]++;
287270252Sluigi			    }
288270252Sluigi			    bad--;
289270252Sluigi			    fail++;
290270252Sluigi			}
291270252Sluigi		    }
292270252Sluigi		    RD(1, "drain %d nodrain %d good %d retry %d fail %d",
293270252Sluigi			drain, nodrain, good, bad, fail);
294270252Sluigi		} else
295270252Sluigi#endif /* !NIC_PARAVIRT */
296262151Sluigi		nic_i = E1000_READ_REG(&adapter->hw, E1000_TDH(0));
297262151Sluigi		if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
298262151Sluigi			D("TDH wrap %d", nic_i);
299262151Sluigi			nic_i -= kring->nkr_num_slots;
300228276Sluigi		}
301262151Sluigi		adapter->next_tx_to_clean = nic_i;
302262151Sluigi		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
303228276Sluigi	}
304231198Sluigi
305262151Sluigi	nm_txsync_finalize(kring);
306262151Sluigi
307227614Sluigi	return 0;
308227614Sluigi}
309227614Sluigi
310227614Sluigi
311227614Sluigi/*
312228276Sluigi * Reconcile kernel and user view of the receive ring.
313227614Sluigi */
314227614Sluigistatic int
315270252Sluigilem_netmap_rxsync(struct netmap_kring *kring, int flags)
316227614Sluigi{
317270252Sluigi	struct netmap_adapter *na = kring->na;
318262151Sluigi	struct ifnet *ifp = na->ifp;
319227614Sluigi	struct netmap_ring *ring = kring->ring;
320262151Sluigi	u_int nm_i;	/* index into the netmap ring */
321262151Sluigi	u_int nic_i;	/* index into the NIC ring */
322262151Sluigi	u_int n;
323262151Sluigi	u_int const lim = kring->nkr_num_slots - 1;
324262151Sluigi	u_int const head = nm_rxsync_prologue(kring);
325262151Sluigi	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
326227614Sluigi
327262151Sluigi	/* device-specific */
328262151Sluigi	struct adapter *adapter = ifp->if_softc;
329270252Sluigi#ifdef NIC_PARAVIRT
330270252Sluigi	struct paravirt_csb *csb = adapter->csb;
331270252Sluigi	uint32_t csb_mode = csb && csb->guest_csb_on;
332270252Sluigi	uint32_t do_host_rxkick = 0;
333270252Sluigi#endif /* NIC_PARAVIRT */
334262151Sluigi
335262151Sluigi	if (head > lim)
336227614Sluigi		return netmap_ring_reinit(kring);
337227614Sluigi
338270252Sluigi#ifdef NIC_PARAVIRT
339270252Sluigi	if (csb_mode) {
340270252Sluigi		force_update = 1;
341270252Sluigi		csb->guest_need_rxkick = 0;
342270252Sluigi	}
343270252Sluigi#endif /* NIC_PARAVIRT */
344227614Sluigi	/* XXX check sync modes */
345227614Sluigi	bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map,
346227614Sluigi			BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
347227614Sluigi
348232238Sluigi	/*
349262151Sluigi	 * First part: import newly received packets.
350231778Sluigi	 */
351232238Sluigi	if (netmap_no_pendintr || force_update) {
352245579Sluigi		uint16_t slot_flags = kring->nkr_slot_flags;
353245579Sluigi
354262151Sluigi		nic_i = adapter->next_rx_desc_to_check;
355262151Sluigi		nm_i = netmap_idx_n2k(kring, nic_i);
356262151Sluigi
357232238Sluigi		for (n = 0; ; n++) {
358262151Sluigi			struct e1000_rx_desc *curr = &adapter->rx_desc_base[nic_i];
359232238Sluigi			uint32_t staterr = le32toh(curr->status);
360232238Sluigi			int len;
361227614Sluigi
362270252Sluigi#ifdef NIC_PARAVIRT
363270252Sluigi			if (csb_mode) {
364270252Sluigi			    if ((staterr & E1000_RXD_STAT_DD) == 0) {
365270252Sluigi				/* don't bother to retry if more than 1 pkt */
366270252Sluigi				if (n > 1)
367270252Sluigi				    break;
368270252Sluigi				csb->guest_need_rxkick = 1;
369270252Sluigi				wmb();
370270252Sluigi				staterr = le32toh(curr->status);
371270252Sluigi				if ((staterr & E1000_RXD_STAT_DD) == 0) {
372270252Sluigi				    break;
373270252Sluigi				} else { /* we are good */
374270252Sluigi				   csb->guest_need_rxkick = 0;
375270252Sluigi				}
376270252Sluigi			    }
377270252Sluigi			} else
378270252Sluigi#endif /* NIC_PARAVIRT */
379232238Sluigi			if ((staterr & E1000_RXD_STAT_DD) == 0)
380232238Sluigi				break;
381232238Sluigi			len = le16toh(curr->length) - 4; // CRC
382232238Sluigi			if (len < 0) {
383270252Sluigi				RD(5, "bogus pkt (%d) size %d nic idx %d", n, len, nic_i);
384232238Sluigi				len = 0;
385232238Sluigi			}
386262151Sluigi			ring->slot[nm_i].len = len;
387262151Sluigi			ring->slot[nm_i].flags = slot_flags;
388232238Sluigi			bus_dmamap_sync(adapter->rxtag,
389262151Sluigi				adapter->rx_buffer_area[nic_i].map,
390262151Sluigi				BUS_DMASYNC_POSTREAD);
391262151Sluigi			nm_i = nm_next(nm_i, lim);
392262151Sluigi			nic_i = nm_next(nic_i, lim);
393227614Sluigi		}
394232238Sluigi		if (n) { /* update the state variables */
395270252Sluigi#ifdef NIC_PARAVIRT
396270252Sluigi			if (csb_mode) {
397270252Sluigi			    if (n > 1) {
398270252Sluigi				/* leave one spare buffer so we avoid rxkicks */
399270252Sluigi				nm_i = nm_prev(nm_i, lim);
400270252Sluigi				nic_i = nm_prev(nic_i, lim);
401270252Sluigi				n--;
402270252Sluigi			    } else {
403270252Sluigi				csb->guest_need_rxkick = 1;
404270252Sluigi			    }
405270252Sluigi			}
406270252Sluigi#endif /* NIC_PARAVIRT */
407262151Sluigi			ND("%d new packets at nic %d nm %d tail %d",
408262151Sluigi				n,
409262151Sluigi				adapter->next_rx_desc_to_check,
410262151Sluigi				netmap_idx_n2k(kring, adapter->next_rx_desc_to_check),
411262151Sluigi				kring->nr_hwtail);
412262151Sluigi			adapter->next_rx_desc_to_check = nic_i;
413262151Sluigi			// ifp->if_ipackets += n;
414262151Sluigi			kring->nr_hwtail = nm_i;
415232238Sluigi		}
416232238Sluigi		kring->nr_kflags &= ~NKR_PENDINTR;
417227614Sluigi	}
418227614Sluigi
419262151Sluigi	/*
420262151Sluigi	 * Second part: skip past packets that userspace has released.
421262151Sluigi	 */
422262151Sluigi	nm_i = kring->nr_hwcur;
423262151Sluigi	if (nm_i != head) {
424262151Sluigi		nic_i = netmap_idx_k2n(kring, nm_i);
425262151Sluigi		for (n = 0; nm_i != head; n++) {
426262151Sluigi			struct netmap_slot *slot = &ring->slot[nm_i];
427229939Sluigi			uint64_t paddr;
428270252Sluigi			void *addr = PNMB(na, slot, &paddr);
429227614Sluigi
430262151Sluigi			struct e1000_rx_desc *curr = &adapter->rx_desc_base[nic_i];
431262151Sluigi			struct em_buffer *rxbuf = &adapter->rx_buffer_area[nic_i];
432231778Sluigi
433270252Sluigi			if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
434262151Sluigi				goto ring_reset;
435262151Sluigi
436227614Sluigi			if (slot->flags & NS_BUF_CHANGED) {
437231796Sluigi				/* buffer has changed, reload map */
438262151Sluigi				curr->buffer_addr = htole64(paddr);
439270252Sluigi				netmap_reload_map(na, adapter->rxtag, rxbuf->map, addr);
440227614Sluigi				slot->flags &= ~NS_BUF_CHANGED;
441227614Sluigi			}
442232238Sluigi			curr->status = 0;
443227614Sluigi			bus_dmamap_sync(adapter->rxtag, rxbuf->map,
444228276Sluigi			    BUS_DMASYNC_PREREAD);
445270252Sluigi#ifdef NIC_PARAVIRT
446270252Sluigi			if (csb_mode && csb->host_rxkick_at == nic_i)
447270252Sluigi				do_host_rxkick = 1;
448270252Sluigi#endif /* NIC_PARAVIRT */
449262151Sluigi			nm_i = nm_next(nm_i, lim);
450262151Sluigi			nic_i = nm_next(nic_i, lim);
451227614Sluigi		}
452262151Sluigi		kring->nr_hwcur = head;
453227614Sluigi		bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map,
454228276Sluigi		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
455227614Sluigi		/*
456227614Sluigi		 * IMPORTANT: we must leave one free slot in the ring,
457262151Sluigi		 * so move nic_i back by one unit
458227614Sluigi		 */
459262151Sluigi		nic_i = nm_prev(nic_i, lim);
460270252Sluigi#ifdef NIC_PARAVIRT
461270252Sluigi		/* set unconditionally, then also kick if needed */
462270252Sluigi		if (csb)
463270252Sluigi			csb->guest_rdt = nic_i;
464270252Sluigi		if (!csb_mode || do_host_rxkick)
465270252Sluigi#endif /* NIC_PARAVIRT */
466262151Sluigi		E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), nic_i);
467227614Sluigi	}
468262151Sluigi
469262151Sluigi	/* tell userspace that there might be new packets */
470262151Sluigi	nm_rxsync_finalize(kring);
471262151Sluigi
472227614Sluigi	return 0;
473262151Sluigi
474262151Sluigiring_reset:
475262151Sluigi	return netmap_ring_reinit(kring);
476227614Sluigi}
477232238Sluigi
478232238Sluigi
479232238Sluigistatic void
480232238Sluigilem_netmap_attach(struct adapter *adapter)
481232238Sluigi{
482232238Sluigi	struct netmap_adapter na;
483232238Sluigi
484232238Sluigi	bzero(&na, sizeof(na));
485232238Sluigi
486232238Sluigi	na.ifp = adapter->ifp;
487262151Sluigi	na.na_flags = NAF_BDG_MAYSLEEP;
488232238Sluigi	na.num_tx_desc = adapter->num_tx_desc;
489232238Sluigi	na.num_rx_desc = adapter->num_rx_desc;
490232238Sluigi	na.nm_txsync = lem_netmap_txsync;
491232238Sluigi	na.nm_rxsync = lem_netmap_rxsync;
492232238Sluigi	na.nm_register = lem_netmap_reg;
493262151Sluigi	na.num_tx_rings = na.num_rx_rings = 1;
494262151Sluigi	netmap_attach(&na);
495232238Sluigi}
496232238Sluigi
497231198Sluigi/* end of file */
498