if_re_netmap.h revision 228276
1/*
2 * Copyright (C) 2011 Luigi Rizzo. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26/*
27 * $FreeBSD: head/sys/dev/netmap/if_re_netmap.h 228276 2011-12-05 12:06:53Z luigi $
28 * $Id: if_re_netmap.h 9802 2011-12-02 18:42:37Z luigi $
29 *
30 * netmap support for if_re
31 */
32
33#include <net/netmap.h>
34#include <sys/selinfo.h>
35#include <vm/vm.h>
36#include <vm/pmap.h>    /* vtophys ? */
37#include <dev/netmap/netmap_kern.h>
38
39static int re_netmap_reg(struct ifnet *, int onoff);
40static int re_netmap_txsync(void *, u_int, int);
41static int re_netmap_rxsync(void *, u_int, int);
42static void re_netmap_lock_wrapper(void *, int, u_int);
43
44static void
45re_netmap_attach(struct rl_softc *sc)
46{
47	struct netmap_adapter na;
48
49	bzero(&na, sizeof(na));
50
51	na.ifp = sc->rl_ifp;
52	na.separate_locks = 0;
53	na.num_tx_desc = sc->rl_ldata.rl_tx_desc_cnt;
54	na.num_rx_desc = sc->rl_ldata.rl_rx_desc_cnt;
55	na.nm_txsync = re_netmap_txsync;
56	na.nm_rxsync = re_netmap_rxsync;
57	na.nm_lock = re_netmap_lock_wrapper;
58	na.nm_register = re_netmap_reg;
59	na.buff_size = NETMAP_BUF_SIZE;
60	netmap_attach(&na, 1);
61}
62
63
64/*
65 * wrapper to export locks to the generic code
66 * We should not use the tx/rx locks
67 */
68static void
69re_netmap_lock_wrapper(void *_a, int what, u_int queueid)
70{
71	struct rl_softc *adapter = _a;
72
73	switch (what) {
74	case NETMAP_CORE_LOCK:
75		RL_LOCK(adapter);
76		break;
77	case NETMAP_CORE_UNLOCK:
78		RL_UNLOCK(adapter);
79		break;
80
81	case NETMAP_TX_LOCK:
82	case NETMAP_RX_LOCK:
83	case NETMAP_TX_UNLOCK:
84	case NETMAP_RX_UNLOCK:
85		D("invalid lock call %d, no tx/rx locks here", what);
86		break;
87	}
88}
89
90
91/*
92 * support for netmap register/unregisted. We are already under core lock.
93 * only called on the first register or the last unregister.
94 */
95static int
96re_netmap_reg(struct ifnet *ifp, int onoff)
97{
98	struct rl_softc *adapter = ifp->if_softc;
99	struct netmap_adapter *na = NA(ifp);
100	int error = 0;
101
102	if (na == NULL)
103		return EINVAL;
104	/* Tell the stack that the interface is no longer active */
105	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
106
107	re_stop(adapter);
108
109	if (onoff) {
110		ifp->if_capenable |= IFCAP_NETMAP;
111
112		/* save if_transmit to restore it later */
113		na->if_transmit = ifp->if_transmit;
114		ifp->if_transmit = netmap_start;
115
116		re_init_locked(adapter);
117
118		if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) == 0) {
119			error = ENOMEM;
120			goto fail;
121		}
122	} else {
123fail:
124		/* restore if_transmit */
125		ifp->if_transmit = na->if_transmit;
126		ifp->if_capenable &= ~IFCAP_NETMAP;
127		re_init_locked(adapter);	/* also enables intr */
128	}
129	return (error);
130}
131
132
133/*
134 * Reconcile kernel and user view of the transmit ring.
135 */
136static int
137re_netmap_txsync(void *a, u_int ring_nr, int do_lock)
138{
139	struct rl_softc *sc = a;
140	struct rl_txdesc *txd = sc->rl_ldata.rl_tx_desc;
141	struct netmap_adapter *na = NA(sc->rl_ifp);
142	struct netmap_kring *kring = &na->tx_rings[ring_nr];
143	struct netmap_ring *ring = kring->ring;
144	int j, k, l, n, lim = kring->nkr_num_slots - 1;
145
146	k = ring->cur;
147	if (k > lim)
148		return netmap_ring_reinit(kring);
149
150	if (do_lock)
151		RL_LOCK(sc);
152
153	/* Sync the TX descriptor list */
154	bus_dmamap_sync(sc->rl_ldata.rl_tx_list_tag,
155            sc->rl_ldata.rl_tx_list_map,
156            BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
157
158	/* XXX move after the transmissions */
159	/* record completed transmissions */
160        for (n = 0, l = sc->rl_ldata.rl_tx_considx;
161	    l != sc->rl_ldata.rl_tx_prodidx;
162	    n++, l = RL_TX_DESC_NXT(sc, l)) {
163		uint32_t cmdstat =
164			le32toh(sc->rl_ldata.rl_tx_list[l].rl_cmdstat);
165		if (cmdstat & RL_TDESC_STAT_OWN)
166			break;
167	}
168	if (n > 0) {
169		sc->rl_ldata.rl_tx_considx = l;
170		sc->rl_ldata.rl_tx_free += n;
171		kring->nr_hwavail += n;
172	}
173
174	/* update avail to what the hardware knows */
175	ring->avail = kring->nr_hwavail;
176
177	j = kring->nr_hwcur;
178	if (j != k) {	/* we have new packets to send */
179		n = 0;
180		l = sc->rl_ldata.rl_tx_prodidx;
181		while (j != k) {
182			struct netmap_slot *slot = &ring->slot[j];
183			struct rl_desc *desc = &sc->rl_ldata.rl_tx_list[l];
184			int cmd = slot->len | RL_TDESC_CMD_EOF |
185				RL_TDESC_CMD_OWN | RL_TDESC_CMD_SOF ;
186			void *addr = NMB(slot);
187			int len = slot->len;
188
189			if (addr == netmap_buffer_base || len > NETMAP_BUF_SIZE) {
190				if (do_lock)
191					RL_UNLOCK(sc);
192				// XXX what about prodidx ?
193				return netmap_ring_reinit(kring);
194			}
195
196			if (l == lim)	/* mark end of ring */
197				cmd |= RL_TDESC_CMD_EOR;
198
199			if (slot->flags & NS_BUF_CHANGED) {
200				uint64_t paddr = vtophys(addr);
201				desc->rl_bufaddr_lo = htole32(RL_ADDR_LO(paddr));
202				desc->rl_bufaddr_hi = htole32(RL_ADDR_HI(paddr));
203				/* buffer has changed, unload and reload map */
204				netmap_reload_map(sc->rl_ldata.rl_tx_mtag,
205					txd[l].tx_dmamap, addr, na->buff_size);
206				slot->flags &= ~NS_BUF_CHANGED;
207			}
208			slot->flags &= ~NS_REPORT;
209			desc->rl_cmdstat = htole32(cmd);
210			bus_dmamap_sync(sc->rl_ldata.rl_tx_mtag,
211				txd[l].tx_dmamap, BUS_DMASYNC_PREWRITE);
212			j = (j == lim) ? 0 : j + 1;
213			l = (l == lim) ? 0 : l + 1;
214			n++;
215		}
216		sc->rl_ldata.rl_tx_prodidx = l;
217		kring->nr_hwcur = k;
218
219		/* decrease avail by number of sent packets */
220		ring->avail -= n;
221		kring->nr_hwavail = ring->avail;
222
223		bus_dmamap_sync(sc->rl_ldata.rl_tx_list_tag,
224		    sc->rl_ldata.rl_tx_list_map,
225		    BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
226
227		/* start ? */
228		CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START);
229	}
230	if (do_lock)
231		RL_UNLOCK(sc);
232	return 0;
233}
234
235
236/*
237 * Reconcile kernel and user view of the receive ring.
238 */
239static int
240re_netmap_rxsync(void *a, u_int ring_nr, int do_lock)
241{
242	struct rl_softc *sc = a;
243	struct rl_rxdesc *rxd = sc->rl_ldata.rl_rx_desc;
244	struct netmap_adapter *na = NA(sc->rl_ifp);
245	struct netmap_kring *kring = &na->rx_rings[ring_nr];
246	struct netmap_ring *ring = kring->ring;
247	int j, k, l, n, lim = kring->nkr_num_slots - 1;
248
249	k = ring->cur;
250	if (k > lim)
251		return netmap_ring_reinit(kring);
252
253	if (do_lock)
254		RL_LOCK(sc);
255	/* XXX check sync modes */
256	bus_dmamap_sync(sc->rl_ldata.rl_rx_list_tag,
257	    sc->rl_ldata.rl_rx_list_map,
258	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
259
260	/*
261	 * The device uses all the buffers in the ring, so we need
262	 * another termination condition in addition to RL_RDESC_STAT_OWN
263	 * cleared (all buffers could have it cleared. The easiest one
264	 * is to limit the amount of data reported up to 'lim'
265	 */
266	l = sc->rl_ldata.rl_rx_prodidx; /* next pkt to check */
267	j = l + kring->nkr_hwofs;
268	for (n = kring->nr_hwavail; n < lim ; n++) {
269		struct rl_desc *cur_rx = &sc->rl_ldata.rl_rx_list[l];
270		uint32_t rxstat = le32toh(cur_rx->rl_cmdstat);
271		uint32_t total_len;
272
273		if ((rxstat & RL_RDESC_STAT_OWN) != 0)
274			break;
275		total_len = rxstat & sc->rl_rxlenmask;
276		/* XXX subtract crc */
277		total_len = (total_len < 4) ? 0 : total_len - 4;
278		kring->ring->slot[j].len = total_len;
279		/*  sync was in re_newbuf() */
280		bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag,
281		    rxd[l].rx_dmamap, BUS_DMASYNC_POSTREAD);
282		j = (j == lim) ? 0 : j + 1;
283		l = (l == lim) ? 0 : l + 1;
284	}
285	if (n != kring->nr_hwavail) {
286		sc->rl_ldata.rl_rx_prodidx = l;
287		sc->rl_ifp->if_ipackets += n - kring->nr_hwavail;
288		kring->nr_hwavail = n;
289	}
290
291	/* skip past packets that userspace has already processed,
292	 * making them available for reception.
293	 * advance nr_hwcur and issue a bus_dmamap_sync on the
294	 * buffers so it is safe to write to them.
295	 * Also increase nr_hwavail
296	 */
297	j = kring->nr_hwcur;
298	if (j != k) {	/* userspace has read some packets. */
299		n = 0;
300		l = kring->nr_hwcur - kring->nkr_hwofs;
301		if (l < 0)
302			l += lim + 1;
303		while (j != k) {
304			struct netmap_slot *slot = ring->slot + j;
305			struct rl_desc *desc = &sc->rl_ldata.rl_rx_list[l];
306			int cmd = na->buff_size | RL_RDESC_CMD_OWN;
307			void *addr = NMB(slot);
308
309			if (addr == netmap_buffer_base) { /* bad buf */
310				if (do_lock)
311					RL_UNLOCK(sc);
312				return netmap_ring_reinit(kring);
313			}
314
315			if (l == lim)	/* mark end of ring */
316				cmd |= RL_RDESC_CMD_EOR;
317
318			desc->rl_cmdstat = htole32(cmd);
319			slot->flags &= ~NS_REPORT;
320			if (slot->flags & NS_BUF_CHANGED) {
321				uint64_t paddr = vtophys(addr);
322				desc->rl_bufaddr_lo = htole32(RL_ADDR_LO(paddr));
323				desc->rl_bufaddr_hi = htole32(RL_ADDR_HI(paddr));
324				netmap_reload_map(sc->rl_ldata.rl_rx_mtag,
325					rxd[l].rx_dmamap, addr, na->buff_size);
326				slot->flags &= ~NS_BUF_CHANGED;
327			}
328			bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag,
329				rxd[l].rx_dmamap, BUS_DMASYNC_PREREAD);
330			j = (j == lim) ? 0 : j + 1;
331			l = (l == lim) ? 0 : l + 1;
332			n++;
333		}
334		kring->nr_hwavail -= n;
335		kring->nr_hwcur = k;
336		/* Flush the RX DMA ring */
337
338		bus_dmamap_sync(sc->rl_ldata.rl_rx_list_tag,
339		    sc->rl_ldata.rl_rx_list_map,
340		    BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
341	}
342	/* tell userspace that there are new packets */
343	ring->avail = kring->nr_hwavail;
344	if (do_lock)
345		RL_UNLOCK(sc);
346	return 0;
347}
348
349/*
350 * Additional routines to init the tx and rx rings.
351 * In other drivers we do that inline in the main code.
352 */
353static void
354re_netmap_tx_init(struct rl_softc *sc)
355{
356	struct rl_txdesc *txd;
357	struct rl_desc *desc;
358	int i, n;
359	struct netmap_adapter *na = NA(sc->rl_ifp);
360	struct netmap_slot *slot = netmap_reset(na, NR_TX, 0, 0);
361
362	/* slot is NULL if we are not in netmap mode */
363	if (!slot)
364		return;
365	/* in netmap mode, overwrite addresses and maps */
366	txd = sc->rl_ldata.rl_tx_desc;
367	desc = sc->rl_ldata.rl_tx_list;
368	n = sc->rl_ldata.rl_tx_desc_cnt;
369
370	/* l points in the netmap ring, i points in the NIC ring */
371	for (i = 0; i < n; i++) {
372		void *addr;
373		uint64_t paddr;
374		struct netmap_kring *kring = &na->tx_rings[0];
375		int l = i + kring->nkr_hwofs;
376
377		if (l >= n)
378			l -= n;
379
380		addr = NMB(slot + l);
381		paddr = vtophys(addr);
382		desc[i].rl_bufaddr_lo = htole32(RL_ADDR_LO(paddr));
383		desc[i].rl_bufaddr_hi = htole32(RL_ADDR_HI(paddr));
384		netmap_load_map(sc->rl_ldata.rl_tx_mtag,
385			txd[i].tx_dmamap, addr, na->buff_size);
386	}
387}
388
389static void
390re_netmap_rx_init(struct rl_softc *sc)
391{
392	struct netmap_adapter *na = NA(sc->rl_ifp);
393	struct netmap_slot *slot = netmap_reset(na, NR_RX, 0, 0);
394	struct rl_desc *desc = sc->rl_ldata.rl_rx_list;
395	uint32_t cmdstat;
396	int i, n;
397
398	if (!slot)
399		return;
400	n = sc->rl_ldata.rl_rx_desc_cnt;
401	for (i = 0; i < n; i++) {
402		void *addr;
403		uint64_t paddr;
404		struct netmap_kring *kring = &na->rx_rings[0];
405		int l = i + kring->nkr_hwofs;
406
407		if (l >= n)
408			l -= n;
409
410		addr = NMB(slot + l);
411		paddr = vtophys(addr);
412		desc[i].rl_bufaddr_lo = htole32(RL_ADDR_LO(paddr));
413		desc[i].rl_bufaddr_hi = htole32(RL_ADDR_HI(paddr));
414		cmdstat = na->buff_size;
415		if (i == n - 1)
416			cmdstat |= RL_RDESC_CMD_EOR;
417		/*
418		 * userspace knows that hwavail packets were ready before the
419		 * reset, so we need to tell the NIC that last hwavail
420		 * descriptors of the ring are still owned by the driver.
421		 */
422		if (i < n - 1 - kring->nr_hwavail) // XXX + 1 ?
423			cmdstat |= RL_RDESC_CMD_OWN;
424		desc[i].rl_cmdstat = htole32(cmdstat);
425
426		netmap_reload_map(sc->rl_ldata.rl_rx_mtag,
427			sc->rl_ldata.rl_rx_desc[i].rx_dmamap,
428			addr, na->buff_size);
429	}
430}
431