if_igb_netmap.h revision 231881
1227614Sluigi/*
2227614Sluigi * Copyright (C) 2011 Universita` di Pisa. 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
26227614Sluigi/*
27227614Sluigi * $FreeBSD: head/sys/dev/netmap/if_igb_netmap.h 231881 2012-02-17 14:09:04Z luigi $
28228276Sluigi * $Id: if_igb_netmap.h 9802 2011-12-02 18:42:37Z luigi $
29227614Sluigi *
30231778Sluigi * netmap modifications for igb contributed by Ahmed Kooli
31227614Sluigi */
32227614Sluigi
33227614Sluigi#include <net/netmap.h>
34227614Sluigi#include <sys/selinfo.h>
35227614Sluigi#include <vm/vm.h>
36227614Sluigi#include <vm/pmap.h>    /* vtophys ? */
37227614Sluigi#include <dev/netmap/netmap_kern.h>
38227614Sluigi
39227614Sluigistatic int	igb_netmap_reg(struct ifnet *, int onoff);
40231594Sluigistatic int	igb_netmap_txsync(struct ifnet *, u_int, int);
41231594Sluigistatic int	igb_netmap_rxsync(struct ifnet *, u_int, int);
42231594Sluigistatic void	igb_netmap_lock_wrapper(struct ifnet *, int, u_int);
43227614Sluigi
44227614Sluigi
45227614Sluigistatic void
46227614Sluigiigb_netmap_attach(struct adapter *adapter)
47227614Sluigi{
48227614Sluigi	struct netmap_adapter na;
49227614Sluigi
50227614Sluigi	bzero(&na, sizeof(na));
51227614Sluigi
52227614Sluigi	na.ifp = adapter->ifp;
53227614Sluigi	na.separate_locks = 1;
54227614Sluigi	na.num_tx_desc = adapter->num_tx_desc;
55227614Sluigi	na.num_rx_desc = adapter->num_rx_desc;
56227614Sluigi	na.nm_txsync = igb_netmap_txsync;
57227614Sluigi	na.nm_rxsync = igb_netmap_rxsync;
58227614Sluigi	na.nm_lock = igb_netmap_lock_wrapper;
59227614Sluigi	na.nm_register = igb_netmap_reg;
60227614Sluigi	netmap_attach(&na, adapter->num_queues);
61227614Sluigi}
62227614Sluigi
63227614Sluigi
64227614Sluigi/*
65227614Sluigi * wrapper to export locks to the generic code
66227614Sluigi */
67227614Sluigistatic void
68231594Sluigiigb_netmap_lock_wrapper(struct ifnet *ifp, int what, u_int queueid)
69227614Sluigi{
70231594Sluigi	struct adapter *adapter = ifp->if_softc;
71227614Sluigi
72227614Sluigi	ASSERT(queueid < adapter->num_queues);
73227614Sluigi	switch (what) {
74227614Sluigi	case NETMAP_CORE_LOCK:
75227614Sluigi		IGB_CORE_LOCK(adapter);
76227614Sluigi		break;
77227614Sluigi	case NETMAP_CORE_UNLOCK:
78227614Sluigi		IGB_CORE_UNLOCK(adapter);
79227614Sluigi		break;
80227614Sluigi	case NETMAP_TX_LOCK:
81227614Sluigi		IGB_TX_LOCK(&adapter->tx_rings[queueid]);
82227614Sluigi		break;
83227614Sluigi	case NETMAP_TX_UNLOCK:
84227614Sluigi		IGB_TX_UNLOCK(&adapter->tx_rings[queueid]);
85227614Sluigi		break;
86227614Sluigi	case NETMAP_RX_LOCK:
87227614Sluigi		IGB_RX_LOCK(&adapter->rx_rings[queueid]);
88227614Sluigi		break;
89227614Sluigi	case NETMAP_RX_UNLOCK:
90227614Sluigi		IGB_RX_UNLOCK(&adapter->rx_rings[queueid]);
91227614Sluigi		break;
92227614Sluigi	}
93227614Sluigi}
94227614Sluigi
95227614Sluigi
96227614Sluigi/*
97231778Sluigi * register-unregister routine
98227614Sluigi */
99227614Sluigistatic int
100227614Sluigiigb_netmap_reg(struct ifnet *ifp, int onoff)
101227614Sluigi{
102227614Sluigi	struct adapter *adapter = ifp->if_softc;
103227614Sluigi	struct netmap_adapter *na = NA(ifp);
104227614Sluigi	int error = 0;
105227614Sluigi
106228276Sluigi	if (na == NULL)
107231778Sluigi		return EINVAL;	/* no netmap support here */
108227614Sluigi
109227614Sluigi	igb_disable_intr(adapter);
110227614Sluigi
111227614Sluigi	/* Tell the stack that the interface is no longer active */
112227614Sluigi	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
113227614Sluigi
114227614Sluigi	if (onoff) {
115227614Sluigi		ifp->if_capenable |= IFCAP_NETMAP;
116227614Sluigi
117227614Sluigi		na->if_transmit = ifp->if_transmit;
118227614Sluigi		ifp->if_transmit = netmap_start;
119227614Sluigi
120227614Sluigi		igb_init_locked(adapter);
121227614Sluigi		if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) == 0) {
122227614Sluigi			error = ENOMEM;
123227614Sluigi			goto fail;
124227614Sluigi		}
125227614Sluigi	} else {
126227614Sluigifail:
127227614Sluigi		/* restore if_transmit */
128227614Sluigi		ifp->if_transmit = na->if_transmit;
129227614Sluigi		ifp->if_capenable &= ~IFCAP_NETMAP;
130231778Sluigi		igb_init_locked(adapter);	/* also enable intr */
131227614Sluigi	}
132227614Sluigi	return (error);
133227614Sluigi}
134227614Sluigi
135227614Sluigi
136227614Sluigi/*
137231778Sluigi * Reconcile hardware and user view of the transmit ring.
138227614Sluigi */
139227614Sluigistatic int
140231594Sluigiigb_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
141227614Sluigi{
142231594Sluigi	struct adapter *adapter = ifp->if_softc;
143227614Sluigi	struct tx_ring *txr = &adapter->tx_rings[ring_nr];
144227614Sluigi	struct netmap_adapter *na = NA(adapter->ifp);
145227614Sluigi	struct netmap_kring *kring = &na->tx_rings[ring_nr];
146227614Sluigi	struct netmap_ring *ring = kring->ring;
147228276Sluigi	int j, k, l, n = 0, lim = kring->nkr_num_slots - 1;
148227614Sluigi
149227614Sluigi	/* generate an interrupt approximately every half ring */
150227614Sluigi	int report_frequency = kring->nkr_num_slots >> 1;
151227614Sluigi
152228276Sluigi	k = ring->cur;
153228276Sluigi	if (k > lim)
154227614Sluigi		return netmap_ring_reinit(kring);
155227614Sluigi
156227614Sluigi	if (do_lock)
157227614Sluigi		IGB_TX_LOCK(txr);
158227614Sluigi	bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
159228276Sluigi	    BUS_DMASYNC_POSTREAD);
160227614Sluigi
161231778Sluigi	/* check for new packets to send.
162231778Sluigi	 * j indexes the netmap ring, l indexes the nic ring, and
163231778Sluigi	 *      j = kring->nr_hwcur, l = E1000_TDT (not tracked),
164231778Sluigi	 *      j == (l + kring->nkr_hwofs) % ring_size
165231778Sluigi	 */
166231778Sluigi	j = kring->nr_hwcur;
167231778Sluigi	if (j != k) {	/* we have packets to send */
168231778Sluigi		/* 82575 needs the queue index added */
169231778Sluigi		u32 olinfo_status =
170231778Sluigi		    (adapter->hw.mac.type == e1000_82575) ? (txr->me << 4) : 0;
171227614Sluigi
172231796Sluigi		l = netmap_tidx_k2n(na, ring_nr, j);
173231881Sluigi		for (n = 0; j != k; n++) {
174227614Sluigi			struct netmap_slot *slot = &ring->slot[j];
175227614Sluigi			union e1000_adv_tx_desc *curr =
176228276Sluigi			    (union e1000_adv_tx_desc *)&txr->tx_base[l];
177231778Sluigi			struct igb_tx_buffer *txbuf = &txr->tx_buffers[l];
178227614Sluigi			int flags = ((slot->flags & NS_REPORT) ||
179227614Sluigi				j == 0 || j == report_frequency) ?
180227614Sluigi					E1000_ADVTXD_DCMD_RS : 0;
181231778Sluigi			uint64_t paddr;
182231778Sluigi			void *addr = PNMB(slot, &paddr);
183227614Sluigi			int len = slot->len;
184227614Sluigi
185227614Sluigi			if (addr == netmap_buffer_base || len > NETMAP_BUF_SIZE) {
186227614Sluigi				if (do_lock)
187227614Sluigi					IGB_TX_UNLOCK(txr);
188227614Sluigi				return netmap_ring_reinit(kring);
189227614Sluigi			}
190227614Sluigi
191227614Sluigi			slot->flags &= ~NS_REPORT;
192231778Sluigi			// XXX set the address unconditionally
193229939Sluigi			curr->read.buffer_addr = htole64(paddr);
194227614Sluigi			curr->read.olinfo_status =
195227614Sluigi			    htole32(olinfo_status |
196227614Sluigi				(len<< E1000_ADVTXD_PAYLEN_SHIFT));
197227614Sluigi			curr->read.cmd_type_len =
198227614Sluigi			    htole32(len | E1000_ADVTXD_DTYP_DATA |
199227614Sluigi				    E1000_ADVTXD_DCMD_IFCS |
200227614Sluigi				    E1000_ADVTXD_DCMD_DEXT |
201227614Sluigi				    E1000_ADVTXD_DCMD_EOP | flags);
202227614Sluigi			if (slot->flags & NS_BUF_CHANGED) {
203228276Sluigi				/* buffer has changed, reload map */
204229939Sluigi				netmap_reload_map(txr->txtag, txbuf->map, addr);
205227614Sluigi				slot->flags &= ~NS_BUF_CHANGED;
206227614Sluigi			}
207227614Sluigi
208227614Sluigi			bus_dmamap_sync(txr->txtag, txbuf->map,
209227614Sluigi				BUS_DMASYNC_PREWRITE);
210227614Sluigi			j = (j == lim) ? 0 : j + 1;
211228276Sluigi			l = (l == lim) ? 0 : l + 1;
212227614Sluigi		}
213227614Sluigi		kring->nr_hwcur = k;
214227614Sluigi
215227614Sluigi		/* decrease avail by number of sent packets */
216228276Sluigi		kring->nr_hwavail -= n;
217227614Sluigi
218228276Sluigi		/* Set the watchdog XXX ? */
219227614Sluigi		txr->queue_status = IGB_QUEUE_WORKING;
220227614Sluigi		txr->watchdog_time = ticks;
221227614Sluigi
222227614Sluigi		bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
223228276Sluigi		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
224227614Sluigi
225228276Sluigi		E1000_WRITE_REG(&adapter->hw, E1000_TDT(txr->me), l);
226227614Sluigi	}
227231778Sluigi
228228276Sluigi	if (n == 0 || kring->nr_hwavail < 1) {
229228276Sluigi		int delta;
230228276Sluigi
231231778Sluigi		/* record completed transmissions using TDH */
232228276Sluigi		l = E1000_READ_REG(&adapter->hw, E1000_TDH(ring_nr));
233231778Sluigi		if (l >= kring->nkr_num_slots) { /* XXX can it happen ? */
234231778Sluigi			D("TDH wrap %d", l);
235228276Sluigi			l -= kring->nkr_num_slots;
236231778Sluigi		}
237228276Sluigi		delta = l - txr->next_to_clean;
238228276Sluigi		if (delta) {
239231778Sluigi			/* some completed, increment hwavail. */
240228276Sluigi			if (delta < 0)
241228276Sluigi				delta += kring->nkr_num_slots;
242228276Sluigi			txr->next_to_clean = l;
243228276Sluigi			kring->nr_hwavail += delta;
244228276Sluigi		}
245228276Sluigi	}
246231778Sluigi	/* update avail to what the hardware knows */
247231778Sluigi	ring->avail = kring->nr_hwavail;
248231778Sluigi
249227614Sluigi	if (do_lock)
250227614Sluigi		IGB_TX_UNLOCK(txr);
251227614Sluigi	return 0;
252227614Sluigi}
253227614Sluigi
254227614Sluigi
255227614Sluigi/*
256227614Sluigi * Reconcile kernel and user view of the receive ring.
257227614Sluigi */
258227614Sluigistatic int
259231594Sluigiigb_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
260227614Sluigi{
261231594Sluigi	struct adapter *adapter = ifp->if_softc;
262227614Sluigi	struct rx_ring *rxr = &adapter->rx_rings[ring_nr];
263227614Sluigi	struct netmap_adapter *na = NA(adapter->ifp);
264227614Sluigi	struct netmap_kring *kring = &na->rx_rings[ring_nr];
265227614Sluigi	struct netmap_ring *ring = kring->ring;
266228276Sluigi	int j, k, l, n, lim = kring->nkr_num_slots - 1;
267227614Sluigi
268228276Sluigi	k = ring->cur;
269228276Sluigi	if (k > lim)
270227614Sluigi		return netmap_ring_reinit(kring);
271227614Sluigi
272227614Sluigi	if (do_lock)
273227614Sluigi		IGB_RX_LOCK(rxr);
274227614Sluigi
275231778Sluigi	/* XXX check sync modes */
276227614Sluigi	bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
277227614Sluigi	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
278227614Sluigi
279231778Sluigi	/* import newly received packets into the netmap ring.
280231778Sluigi	 * j is an index in the netmap ring, l in the NIC ring, and
281231778Sluigi	 *      j = (kring->nr_hwcur + kring->nr_hwavail) % ring_size
282231778Sluigi	 *      l = rxr->next_to_check;
283231778Sluigi	 * and
284231778Sluigi	 *      j == (l + kring->nkr_hwofs) % ring_size
285231778Sluigi	 */
286228276Sluigi	l = rxr->next_to_check;
287231796Sluigi	j = netmap_ridx_n2k(na, ring_nr, l);
288227614Sluigi	for (n = 0; ; n++) {
289228276Sluigi		union e1000_adv_rx_desc *curr = &rxr->rx_base[l];
290227614Sluigi		uint32_t staterr = le32toh(curr->wb.upper.status_error);
291227614Sluigi
292227614Sluigi		if ((staterr & E1000_RXD_STAT_DD) == 0)
293227614Sluigi			break;
294227614Sluigi		ring->slot[j].len = le16toh(curr->wb.upper.length);
295227614Sluigi		bus_dmamap_sync(rxr->ptag,
296228276Sluigi			rxr->rx_buffers[l].pmap, BUS_DMASYNC_POSTREAD);
297227614Sluigi		j = (j == lim) ? 0 : j + 1;
298228276Sluigi		l = (l == lim) ? 0 : l + 1;
299227614Sluigi	}
300227614Sluigi	if (n) {
301228276Sluigi		rxr->next_to_check = l;
302227614Sluigi		kring->nr_hwavail += n;
303227614Sluigi	}
304227614Sluigi
305231778Sluigi	/* skip past packets that userspace has already processed */
306227614Sluigi	j = kring->nr_hwcur;
307231778Sluigi	if (j != k) { /* userspace has read some packets. */
308231796Sluigi		l = netmap_ridx_k2n(na, ring_nr, j);
309231881Sluigi		for (n = 0; j != k; n++) {
310227614Sluigi			struct netmap_slot *slot = ring->slot + j;
311228276Sluigi			union e1000_adv_rx_desc *curr = &rxr->rx_base[l];
312228276Sluigi			struct igb_rx_buf *rxbuf = rxr->rx_buffers + l;
313229939Sluigi			uint64_t paddr;
314229939Sluigi			void *addr = PNMB(slot, &paddr);
315227614Sluigi
316227614Sluigi			if (addr == netmap_buffer_base) { /* bad buf */
317227614Sluigi				if (do_lock)
318227614Sluigi					IGB_RX_UNLOCK(rxr);
319227614Sluigi				return netmap_ring_reinit(kring);
320227614Sluigi			}
321227614Sluigi
322227614Sluigi			curr->wb.upper.status_error = 0;
323229939Sluigi			curr->read.pkt_addr = htole64(paddr);
324227614Sluigi			if (slot->flags & NS_BUF_CHANGED) {
325229939Sluigi				netmap_reload_map(rxr->ptag, rxbuf->pmap, addr);
326227614Sluigi				slot->flags &= ~NS_BUF_CHANGED;
327227614Sluigi			}
328227614Sluigi
329227614Sluigi			bus_dmamap_sync(rxr->ptag, rxbuf->pmap,
330227614Sluigi				BUS_DMASYNC_PREREAD);
331227614Sluigi
332227614Sluigi			j = (j == lim) ? 0 : j + 1;
333228276Sluigi			l = (l == lim) ? 0 : l + 1;
334227614Sluigi		}
335227614Sluigi		kring->nr_hwavail -= n;
336231778Sluigi		kring->nr_hwcur = k;
337227614Sluigi		bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
338227614Sluigi			BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
339231778Sluigi		/*
340231778Sluigi		 * IMPORTANT: we must leave one free slot in the ring,
341228276Sluigi		 * so move l back by one unit
342227614Sluigi		 */
343228276Sluigi		l = (l == 0) ? lim : l - 1;
344228276Sluigi		E1000_WRITE_REG(&adapter->hw, E1000_RDT(rxr->me), l);
345227614Sluigi	}
346227614Sluigi	/* tell userspace that there are new packets */
347227614Sluigi	ring->avail = kring->nr_hwavail ;
348227614Sluigi	if (do_lock)
349227614Sluigi		IGB_RX_UNLOCK(rxr);
350227614Sluigi	return 0;
351227614Sluigi}
352231778Sluigi/* end of file */
353