1221828Sgrehan/*-
2221828Sgrehan * Copyright (c) 2011 NetApp, Inc.
3221828Sgrehan * All rights reserved.
4221828Sgrehan *
5221828Sgrehan * Redistribution and use in source and binary forms, with or without
6221828Sgrehan * modification, are permitted provided that the following conditions
7221828Sgrehan * are met:
8221828Sgrehan * 1. Redistributions of source code must retain the above copyright
9221828Sgrehan *    notice, this list of conditions and the following disclaimer.
10221828Sgrehan * 2. Redistributions in binary form must reproduce the above copyright
11221828Sgrehan *    notice, this list of conditions and the following disclaimer in the
12221828Sgrehan *    documentation and/or other materials provided with the distribution.
13221828Sgrehan *
14221828Sgrehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15221828Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16221828Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17221828Sgrehan * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18221828Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19221828Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20221828Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21221828Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22221828Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23221828Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24221828Sgrehan * SUCH DAMAGE.
25221828Sgrehan *
26221828Sgrehan * $FreeBSD: stable/10/usr.sbin/bhyve/pci_virtio_net.c 307183 2016-10-13 06:32:21Z np $
27221828Sgrehan */
28221828Sgrehan
29221828Sgrehan#include <sys/cdefs.h>
30221828Sgrehan__FBSDID("$FreeBSD: stable/10/usr.sbin/bhyve/pci_virtio_net.c 307183 2016-10-13 06:32:21Z np $");
31221828Sgrehan
32221828Sgrehan#include <sys/param.h>
33221828Sgrehan#include <sys/linker_set.h>
34221828Sgrehan#include <sys/select.h>
35221828Sgrehan#include <sys/uio.h>
36221828Sgrehan#include <sys/ioctl.h>
37282839Smav#include <machine/atomic.h>
38252682Sgrehan#include <net/ethernet.h>
39294294Sgnn#ifndef NETMAP_WITH_LIBS
40294294Sgnn#define NETMAP_WITH_LIBS
41294294Sgnn#endif
42294294Sgnn#include <net/netmap_user.h>
43221828Sgrehan
44221828Sgrehan#include <errno.h>
45221828Sgrehan#include <fcntl.h>
46221828Sgrehan#include <stdio.h>
47221828Sgrehan#include <stdlib.h>
48221828Sgrehan#include <stdint.h>
49221828Sgrehan#include <string.h>
50221828Sgrehan#include <strings.h>
51221828Sgrehan#include <unistd.h>
52221828Sgrehan#include <assert.h>
53221828Sgrehan#include <md5.h>
54221828Sgrehan#include <pthread.h>
55249917Sgrehan#include <pthread_np.h>
56221828Sgrehan
57244167Sgrehan#include "bhyverun.h"
58221828Sgrehan#include "pci_emul.h"
59221828Sgrehan#include "mevent.h"
60221828Sgrehan#include "virtio.h"
61221828Sgrehan
62249917Sgrehan#define VTNET_RINGSZ	1024
63221828Sgrehan
64295124Sgrehan#define VTNET_MAXSEGS	256
65221828Sgrehan
66221828Sgrehan/*
67253440Sgrehan * Host capabilities.  Note that we only offer a few of these.
68221828Sgrehan */
69253440Sgrehan#define	VIRTIO_NET_F_CSUM	(1 <<  0) /* host handles partial cksum */
70253440Sgrehan#define	VIRTIO_NET_F_GUEST_CSUM	(1 <<  1) /* guest handles partial cksum */
71253440Sgrehan#define	VIRTIO_NET_F_MAC	(1 <<  5) /* host supplies MAC */
72253440Sgrehan#define	VIRTIO_NET_F_GSO_DEPREC	(1 <<  6) /* deprecated: host handles GSO */
73253440Sgrehan#define	VIRTIO_NET_F_GUEST_TSO4	(1 <<  7) /* guest can rcv TSOv4 */
74253440Sgrehan#define	VIRTIO_NET_F_GUEST_TSO6	(1 <<  8) /* guest can rcv TSOv6 */
75253440Sgrehan#define	VIRTIO_NET_F_GUEST_ECN	(1 <<  9) /* guest can rcv TSO with ECN */
76253440Sgrehan#define	VIRTIO_NET_F_GUEST_UFO	(1 << 10) /* guest can rcv UFO */
77253440Sgrehan#define	VIRTIO_NET_F_HOST_TSO4	(1 << 11) /* host can rcv TSOv4 */
78253440Sgrehan#define	VIRTIO_NET_F_HOST_TSO6	(1 << 12) /* host can rcv TSOv6 */
79253440Sgrehan#define	VIRTIO_NET_F_HOST_ECN	(1 << 13) /* host can rcv TSO with ECN */
80253440Sgrehan#define	VIRTIO_NET_F_HOST_UFO	(1 << 14) /* host can rcv UFO */
81253440Sgrehan#define	VIRTIO_NET_F_MRG_RXBUF	(1 << 15) /* host can merge RX buffers */
82253440Sgrehan#define	VIRTIO_NET_F_STATUS	(1 << 16) /* config status field available */
83253440Sgrehan#define	VIRTIO_NET_F_CTRL_VQ	(1 << 17) /* control channel available */
84253440Sgrehan#define	VIRTIO_NET_F_CTRL_RX	(1 << 18) /* control channel RX mode support */
85253440Sgrehan#define	VIRTIO_NET_F_CTRL_VLAN	(1 << 19) /* control channel VLAN filtering */
86253440Sgrehan#define	VIRTIO_NET_F_GUEST_ANNOUNCE \
87253440Sgrehan				(1 << 21) /* guest can send gratuitous pkts */
88221828Sgrehan
89253440Sgrehan#define VTNET_S_HOSTCAPS      \
90253440Sgrehan  ( VIRTIO_NET_F_MAC | VIRTIO_NET_F_MRG_RXBUF | VIRTIO_NET_F_STATUS | \
91295124Sgrehan    VIRTIO_F_NOTIFY_ON_EMPTY | VIRTIO_RING_F_INDIRECT_DESC)
92221828Sgrehan
93221828Sgrehan/*
94253440Sgrehan * PCI config-space "registers"
95221828Sgrehan */
96253440Sgrehanstruct virtio_net_config {
97253440Sgrehan	uint8_t  mac[6];
98253440Sgrehan	uint16_t status;
99253440Sgrehan} __packed;
100221828Sgrehan
101221828Sgrehan/*
102221828Sgrehan * Queue definitions.
103221828Sgrehan */
104221828Sgrehan#define VTNET_RXQ	0
105221828Sgrehan#define VTNET_TXQ	1
106253440Sgrehan#define VTNET_CTLQ	2	/* NB: not yet supported */
107221828Sgrehan
108221828Sgrehan#define VTNET_MAXQ	3
109221828Sgrehan
110221828Sgrehan/*
111221828Sgrehan * Fixed network header size
112221828Sgrehan */
113221828Sgrehanstruct virtio_net_rxhdr {
114221828Sgrehan	uint8_t		vrh_flags;
115221828Sgrehan	uint8_t		vrh_gso_type;
116221828Sgrehan	uint16_t	vrh_hdr_len;
117221828Sgrehan	uint16_t	vrh_gso_size;
118221828Sgrehan	uint16_t	vrh_csum_start;
119221828Sgrehan	uint16_t	vrh_csum_offset;
120221828Sgrehan	uint16_t	vrh_bufs;
121221828Sgrehan} __packed;
122221828Sgrehan
123221828Sgrehan/*
124221828Sgrehan * Debug printf
125221828Sgrehan */
126221828Sgrehanstatic int pci_vtnet_debug;
127221828Sgrehan#define DPRINTF(params) if (pci_vtnet_debug) printf params
128221828Sgrehan#define WPRINTF(params) printf params
129221828Sgrehan
130221828Sgrehan/*
131221828Sgrehan * Per-device softc
132221828Sgrehan */
133221828Sgrehanstruct pci_vtnet_softc {
134253440Sgrehan	struct virtio_softc vsc_vs;
135253440Sgrehan	struct vqueue_info vsc_queues[VTNET_MAXQ - 1];
136221828Sgrehan	pthread_mutex_t vsc_mtx;
137221828Sgrehan	struct mevent	*vsc_mevp;
138221828Sgrehan
139221828Sgrehan	int		vsc_tapfd;
140294294Sgnn	struct nm_desc	*vsc_nmd;
141294294Sgnn
142221828Sgrehan	int		vsc_rx_ready;
143253440Sgrehan	volatile int	resetting;	/* set and checked outside lock */
144221828Sgrehan
145271685Sgrehan	uint64_t	vsc_features;	/* negotiated features */
146271685Sgrehan
147253440Sgrehan	struct virtio_net_config vsc_config;
148221828Sgrehan
149250083Sneel	pthread_mutex_t	rx_mtx;
150250083Sneel	int		rx_in_progress;
151271685Sgrehan	int		rx_vhdrlen;
152271685Sgrehan	int		rx_merge;	/* merged rx bufs in use */
153250083Sneel
154249917Sgrehan	pthread_t 	tx_tid;
155249917Sgrehan	pthread_mutex_t	tx_mtx;
156249917Sgrehan	pthread_cond_t	tx_cond;
157250083Sneel	int		tx_in_progress;
158294294Sgnn
159294294Sgnn	void (*pci_vtnet_rx)(struct pci_vtnet_softc *sc);
160294294Sgnn	void (*pci_vtnet_tx)(struct pci_vtnet_softc *sc, struct iovec *iov,
161294294Sgnn			     int iovcnt, int len);
162221828Sgrehan};
163221828Sgrehan
164253440Sgrehanstatic void pci_vtnet_reset(void *);
165253440Sgrehan/* static void pci_vtnet_notify(void *, struct vqueue_info *); */
166253440Sgrehanstatic int pci_vtnet_cfgread(void *, int, int, uint32_t *);
167253440Sgrehanstatic int pci_vtnet_cfgwrite(void *, int, int, uint32_t);
168271685Sgrehanstatic void pci_vtnet_neg_features(void *, uint64_t);
169246109Sneel
170253440Sgrehanstatic struct virtio_consts vtnet_vi_consts = {
171253440Sgrehan	"vtnet",		/* our name */
172253440Sgrehan	VTNET_MAXQ - 1,		/* we currently support 2 virtqueues */
173253440Sgrehan	sizeof(struct virtio_net_config), /* config reg size */
174253440Sgrehan	pci_vtnet_reset,	/* reset */
175253440Sgrehan	NULL,			/* device-wide qnotify -- not used */
176253440Sgrehan	pci_vtnet_cfgread,	/* read PCI config */
177253440Sgrehan	pci_vtnet_cfgwrite,	/* write PCI config */
178271685Sgrehan	pci_vtnet_neg_features,	/* apply negotiated features */
179253440Sgrehan	VTNET_S_HOSTCAPS,	/* our capabilities */
180253440Sgrehan};
181221828Sgrehan
182250083Sneel/*
183250083Sneel * If the transmit thread is active then stall until it is done.
184250083Sneel */
185244160Sgrehanstatic void
186250083Sneelpci_vtnet_txwait(struct pci_vtnet_softc *sc)
187250083Sneel{
188250083Sneel
189250083Sneel	pthread_mutex_lock(&sc->tx_mtx);
190250083Sneel	while (sc->tx_in_progress) {
191250083Sneel		pthread_mutex_unlock(&sc->tx_mtx);
192250083Sneel		usleep(10000);
193250083Sneel		pthread_mutex_lock(&sc->tx_mtx);
194250083Sneel	}
195250083Sneel	pthread_mutex_unlock(&sc->tx_mtx);
196250083Sneel}
197250083Sneel
198250083Sneel/*
199250083Sneel * If the receive thread is active then stall until it is done.
200250083Sneel */
201250083Sneelstatic void
202250083Sneelpci_vtnet_rxwait(struct pci_vtnet_softc *sc)
203250083Sneel{
204250083Sneel
205250083Sneel	pthread_mutex_lock(&sc->rx_mtx);
206250083Sneel	while (sc->rx_in_progress) {
207250083Sneel		pthread_mutex_unlock(&sc->rx_mtx);
208250083Sneel		usleep(10000);
209250083Sneel		pthread_mutex_lock(&sc->rx_mtx);
210250083Sneel	}
211250083Sneel	pthread_mutex_unlock(&sc->rx_mtx);
212250083Sneel}
213250083Sneel
214250083Sneelstatic void
215253440Sgrehanpci_vtnet_reset(void *vsc)
216221828Sgrehan{
217253440Sgrehan	struct pci_vtnet_softc *sc = vsc;
218244160Sgrehan
219253440Sgrehan	DPRINTF(("vtnet: device reset requested !\n"));
220249917Sgrehan
221253440Sgrehan	sc->resetting = 1;
222250083Sneel
223253440Sgrehan	/*
224253440Sgrehan	 * Wait for the transmit and receive threads to finish their
225253440Sgrehan	 * processing.
226253440Sgrehan	 */
227253440Sgrehan	pci_vtnet_txwait(sc);
228253440Sgrehan	pci_vtnet_rxwait(sc);
229250083Sneel
230253440Sgrehan	sc->vsc_rx_ready = 0;
231271685Sgrehan	sc->rx_merge = 1;
232271685Sgrehan	sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr);
233250086Sneel
234253440Sgrehan	/* now reset rings, MSI-X vectors, and negotiated capabilities */
235253440Sgrehan	vi_reset_dev(&sc->vsc_vs);
236250086Sneel
237253440Sgrehan	sc->resetting = 0;
238221828Sgrehan}
239221828Sgrehan
240221828Sgrehan/*
241221828Sgrehan * Called to send a buffer chain out to the tap device
242221828Sgrehan */
243221828Sgrehanstatic void
244221828Sgrehanpci_vtnet_tap_tx(struct pci_vtnet_softc *sc, struct iovec *iov, int iovcnt,
245221828Sgrehan		 int len)
246221828Sgrehan{
247253440Sgrehan	static char pad[60]; /* all zero bytes */
248221828Sgrehan
249221828Sgrehan	if (sc->vsc_tapfd == -1)
250221828Sgrehan		return;
251221828Sgrehan
252221828Sgrehan	/*
253221828Sgrehan	 * If the length is < 60, pad out to that and add the
254221828Sgrehan	 * extra zero'd segment to the iov. It is guaranteed that
255221828Sgrehan	 * there is always an extra iov available by the caller.
256221828Sgrehan	 */
257221828Sgrehan	if (len < 60) {
258221828Sgrehan		iov[iovcnt].iov_base = pad;
259221828Sgrehan		iov[iovcnt].iov_len = 60 - len;
260221828Sgrehan		iovcnt++;
261221828Sgrehan	}
262221828Sgrehan	(void) writev(sc->vsc_tapfd, iov, iovcnt);
263221828Sgrehan}
264221828Sgrehan
265221828Sgrehan/*
266221828Sgrehan *  Called when there is read activity on the tap file descriptor.
267221828Sgrehan * Each buffer posted by the guest is assumed to be able to contain
268221828Sgrehan * an entire ethernet frame + rx header.
269221828Sgrehan *  MP note: the dummybuf is only used for discarding frames, so there
270221828Sgrehan * is no need for it to be per-vtnet or locked.
271221828Sgrehan */
272221828Sgrehanstatic uint8_t dummybuf[2048];
273221828Sgrehan
274271685Sgrehanstatic __inline struct iovec *
275271685Sgrehanrx_iov_trim(struct iovec *iov, int *niov, int tlen)
276271685Sgrehan{
277271685Sgrehan	struct iovec *riov;
278271685Sgrehan
279271685Sgrehan	/* XXX short-cut: assume first segment is >= tlen */
280271685Sgrehan	assert(iov[0].iov_len >= tlen);
281271685Sgrehan
282271685Sgrehan	iov[0].iov_len -= tlen;
283271685Sgrehan	if (iov[0].iov_len == 0) {
284271685Sgrehan		assert(*niov > 1);
285271685Sgrehan		*niov -= 1;
286271685Sgrehan		riov = &iov[1];
287271685Sgrehan	} else {
288271685Sgrehan		iov[0].iov_base = (void *)((uintptr_t)iov[0].iov_base + tlen);
289271685Sgrehan		riov = &iov[0];
290271685Sgrehan	}
291271685Sgrehan
292271685Sgrehan	return (riov);
293271685Sgrehan}
294271685Sgrehan
295221828Sgrehanstatic void
296221828Sgrehanpci_vtnet_tap_rx(struct pci_vtnet_softc *sc)
297221828Sgrehan{
298271685Sgrehan	struct iovec iov[VTNET_MAXSEGS], *riov;
299253440Sgrehan	struct vqueue_info *vq;
300271685Sgrehan	void *vrx;
301271685Sgrehan	int len, n;
302280743Smav	uint16_t idx;
303221828Sgrehan
304221828Sgrehan	/*
305221828Sgrehan	 * Should never be called without a valid tap fd
306221828Sgrehan	 */
307221828Sgrehan	assert(sc->vsc_tapfd != -1);
308221828Sgrehan
309221828Sgrehan	/*
310221828Sgrehan	 * But, will be called when the rx ring hasn't yet
311250083Sneel	 * been set up or the guest is resetting the device.
312221828Sgrehan	 */
313250083Sneel	if (!sc->vsc_rx_ready || sc->resetting) {
314221828Sgrehan		/*
315221828Sgrehan		 * Drop the packet and try later.
316221828Sgrehan		 */
317221828Sgrehan		(void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf));
318221828Sgrehan		return;
319221828Sgrehan	}
320221828Sgrehan
321221828Sgrehan	/*
322253440Sgrehan	 * Check for available rx buffers
323221828Sgrehan	 */
324253440Sgrehan	vq = &sc->vsc_queues[VTNET_RXQ];
325253440Sgrehan	if (!vq_has_descs(vq)) {
326221828Sgrehan		/*
327253440Sgrehan		 * Drop the packet and try later.  Interrupt on
328253440Sgrehan		 * empty, if that's negotiated.
329221828Sgrehan		 */
330221828Sgrehan		(void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf));
331253440Sgrehan		vq_endchains(vq, 1);
332221828Sgrehan		return;
333221828Sgrehan	}
334221828Sgrehan
335253440Sgrehan	do {
336221828Sgrehan		/*
337271685Sgrehan		 * Get descriptor chain.
338221828Sgrehan		 */
339280743Smav		n = vq_getchain(vq, &idx, iov, VTNET_MAXSEGS, NULL);
340271685Sgrehan		assert(n >= 1 && n <= VTNET_MAXSEGS);
341221828Sgrehan
342221828Sgrehan		/*
343221828Sgrehan		 * Get a pointer to the rx header, and use the
344221828Sgrehan		 * data immediately following it for the packet buffer.
345221828Sgrehan		 */
346271685Sgrehan		vrx = iov[0].iov_base;
347271685Sgrehan		riov = rx_iov_trim(iov, &n, sc->rx_vhdrlen);
348221828Sgrehan
349271685Sgrehan		len = readv(sc->vsc_tapfd, riov, n);
350221828Sgrehan
351221828Sgrehan		if (len < 0 && errno == EWOULDBLOCK) {
352253440Sgrehan			/*
353253440Sgrehan			 * No more packets, but still some avail ring
354253440Sgrehan			 * entries.  Interrupt if needed/appropriate.
355253440Sgrehan			 */
356280743Smav			vq_retchain(vq);
357253440Sgrehan			vq_endchains(vq, 0);
358253440Sgrehan			return;
359221828Sgrehan		}
360221828Sgrehan
361221828Sgrehan		/*
362221828Sgrehan		 * The only valid field in the rx packet header is the
363271685Sgrehan		 * number of buffers if merged rx bufs were negotiated.
364221828Sgrehan		 */
365271685Sgrehan		memset(vrx, 0, sc->rx_vhdrlen);
366221828Sgrehan
367271685Sgrehan		if (sc->rx_merge) {
368271685Sgrehan			struct virtio_net_rxhdr *vrxh;
369271685Sgrehan
370271685Sgrehan			vrxh = vrx;
371271685Sgrehan			vrxh->vrh_bufs = 1;
372271685Sgrehan		}
373271685Sgrehan
374221828Sgrehan		/*
375253440Sgrehan		 * Release this chain and handle more chains.
376221828Sgrehan		 */
377280743Smav		vq_relchain(vq, idx, len + sc->rx_vhdrlen);
378253440Sgrehan	} while (vq_has_descs(vq));
379221828Sgrehan
380253440Sgrehan	/* Interrupt if needed, including for NOTIFY_ON_EMPTY. */
381253440Sgrehan	vq_endchains(vq, 1);
382221828Sgrehan}
383221828Sgrehan
384294294Sgnnstatic int
385294294Sgnnpci_vtnet_netmap_writev(struct nm_desc *nmd, struct iovec *iov, int iovcnt)
386294294Sgnn{
387294294Sgnn	int r, i;
388294294Sgnn	int len = 0;
389294294Sgnn
390294294Sgnn	for (r = nmd->cur_tx_ring; ; ) {
391294294Sgnn		struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, r);
392294294Sgnn		uint32_t cur, idx;
393294294Sgnn		char *buf;
394294294Sgnn
395294294Sgnn		if (nm_ring_empty(ring)) {
396294294Sgnn			r++;
397294294Sgnn			if (r > nmd->last_tx_ring)
398294294Sgnn				r = nmd->first_tx_ring;
399294294Sgnn			if (r == nmd->cur_rx_ring)
400294294Sgnn				break;
401294294Sgnn			continue;
402294294Sgnn		}
403294294Sgnn		cur = ring->cur;
404294294Sgnn		idx = ring->slot[cur].buf_idx;
405294294Sgnn		buf = NETMAP_BUF(ring, idx);
406294294Sgnn
407294294Sgnn		for (i = 0; i < iovcnt; i++) {
408294294Sgnn			memcpy(&buf[len], iov[i].iov_base, iov[i].iov_len);
409294294Sgnn			len += iov[i].iov_len;
410294294Sgnn		}
411294294Sgnn		ring->slot[cur].len = len;
412294294Sgnn		ring->head = ring->cur = nm_ring_next(ring, cur);
413294294Sgnn		nmd->cur_tx_ring = r;
414294294Sgnn		ioctl(nmd->fd, NIOCTXSYNC, NULL);
415294294Sgnn		break;
416294294Sgnn	}
417294294Sgnn
418294294Sgnn	return (len);
419294294Sgnn}
420294294Sgnn
421294294Sgnnstatic inline int
422294294Sgnnpci_vtnet_netmap_readv(struct nm_desc *nmd, struct iovec *iov, int iovcnt)
423294294Sgnn{
424294294Sgnn	int len = 0;
425294294Sgnn	int i = 0;
426294294Sgnn	int r;
427294294Sgnn
428294294Sgnn	for (r = nmd->cur_rx_ring; ; ) {
429294294Sgnn		struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, r);
430294294Sgnn		uint32_t cur, idx;
431294294Sgnn		char *buf;
432294294Sgnn		size_t left;
433294294Sgnn
434294294Sgnn		if (nm_ring_empty(ring)) {
435294294Sgnn			r++;
436294294Sgnn			if (r > nmd->last_rx_ring)
437294294Sgnn				r = nmd->first_rx_ring;
438294294Sgnn			if (r == nmd->cur_rx_ring)
439294294Sgnn				break;
440294294Sgnn			continue;
441294294Sgnn		}
442294294Sgnn		cur = ring->cur;
443294294Sgnn		idx = ring->slot[cur].buf_idx;
444294294Sgnn		buf = NETMAP_BUF(ring, idx);
445294294Sgnn		left = ring->slot[cur].len;
446294294Sgnn
447294294Sgnn		for (i = 0; i < iovcnt && left > 0; i++) {
448294294Sgnn			if (iov[i].iov_len > left)
449294294Sgnn				iov[i].iov_len = left;
450294294Sgnn			memcpy(iov[i].iov_base, &buf[len], iov[i].iov_len);
451294294Sgnn			len += iov[i].iov_len;
452294294Sgnn			left -= iov[i].iov_len;
453294294Sgnn		}
454294294Sgnn		ring->head = ring->cur = nm_ring_next(ring, cur);
455294294Sgnn		nmd->cur_rx_ring = r;
456294294Sgnn		ioctl(nmd->fd, NIOCRXSYNC, NULL);
457294294Sgnn		break;
458294294Sgnn	}
459294294Sgnn	for (; i < iovcnt; i++)
460294294Sgnn		iov[i].iov_len = 0;
461294294Sgnn
462294294Sgnn	return (len);
463294294Sgnn}
464294294Sgnn
465294294Sgnn/*
466294294Sgnn * Called to send a buffer chain out to the vale port
467294294Sgnn */
468221828Sgrehanstatic void
469294294Sgnnpci_vtnet_netmap_tx(struct pci_vtnet_softc *sc, struct iovec *iov, int iovcnt,
470294294Sgnn		    int len)
471221828Sgrehan{
472294294Sgnn	static char pad[60]; /* all zero bytes */
473294294Sgnn
474294294Sgnn	if (sc->vsc_nmd == NULL)
475294294Sgnn		return;
476294294Sgnn
477294294Sgnn	/*
478294294Sgnn	 * If the length is < 60, pad out to that and add the
479294294Sgnn	 * extra zero'd segment to the iov. It is guaranteed that
480294294Sgnn	 * there is always an extra iov available by the caller.
481294294Sgnn	 */
482294294Sgnn	if (len < 60) {
483294294Sgnn		iov[iovcnt].iov_base = pad;
484294294Sgnn		iov[iovcnt].iov_len = 60 - len;
485294294Sgnn		iovcnt++;
486294294Sgnn	}
487294294Sgnn	(void) pci_vtnet_netmap_writev(sc->vsc_nmd, iov, iovcnt);
488294294Sgnn}
489294294Sgnn
490294294Sgnnstatic void
491294294Sgnnpci_vtnet_netmap_rx(struct pci_vtnet_softc *sc)
492294294Sgnn{
493294294Sgnn	struct iovec iov[VTNET_MAXSEGS], *riov;
494294294Sgnn	struct vqueue_info *vq;
495294294Sgnn	void *vrx;
496294294Sgnn	int len, n;
497294294Sgnn	uint16_t idx;
498294294Sgnn
499294294Sgnn	/*
500294294Sgnn	 * Should never be called without a valid netmap descriptor
501294294Sgnn	 */
502294294Sgnn	assert(sc->vsc_nmd != NULL);
503294294Sgnn
504294294Sgnn	/*
505294294Sgnn	 * But, will be called when the rx ring hasn't yet
506294294Sgnn	 * been set up or the guest is resetting the device.
507294294Sgnn	 */
508294294Sgnn	if (!sc->vsc_rx_ready || sc->resetting) {
509294294Sgnn		/*
510294294Sgnn		 * Drop the packet and try later.
511294294Sgnn		 */
512294294Sgnn		(void) nm_nextpkt(sc->vsc_nmd, (void *)dummybuf);
513294294Sgnn		return;
514294294Sgnn	}
515294294Sgnn
516294294Sgnn	/*
517294294Sgnn	 * Check for available rx buffers
518294294Sgnn	 */
519294294Sgnn	vq = &sc->vsc_queues[VTNET_RXQ];
520294294Sgnn	if (!vq_has_descs(vq)) {
521294294Sgnn		/*
522294294Sgnn		 * Drop the packet and try later.  Interrupt on
523294294Sgnn		 * empty, if that's negotiated.
524294294Sgnn		 */
525294294Sgnn		(void) nm_nextpkt(sc->vsc_nmd, (void *)dummybuf);
526294294Sgnn		vq_endchains(vq, 1);
527294294Sgnn		return;
528294294Sgnn	}
529294294Sgnn
530294294Sgnn	do {
531294294Sgnn		/*
532294294Sgnn		 * Get descriptor chain.
533294294Sgnn		 */
534294294Sgnn		n = vq_getchain(vq, &idx, iov, VTNET_MAXSEGS, NULL);
535294294Sgnn		assert(n >= 1 && n <= VTNET_MAXSEGS);
536294294Sgnn
537294294Sgnn		/*
538294294Sgnn		 * Get a pointer to the rx header, and use the
539294294Sgnn		 * data immediately following it for the packet buffer.
540294294Sgnn		 */
541294294Sgnn		vrx = iov[0].iov_base;
542294294Sgnn		riov = rx_iov_trim(iov, &n, sc->rx_vhdrlen);
543294294Sgnn
544294294Sgnn		len = pci_vtnet_netmap_readv(sc->vsc_nmd, riov, n);
545294294Sgnn
546294294Sgnn		if (len == 0) {
547294294Sgnn			/*
548294294Sgnn			 * No more packets, but still some avail ring
549294294Sgnn			 * entries.  Interrupt if needed/appropriate.
550294294Sgnn			 */
551294294Sgnn			vq_endchains(vq, 0);
552294294Sgnn			return;
553294294Sgnn		}
554294294Sgnn
555294294Sgnn		/*
556294294Sgnn		 * The only valid field in the rx packet header is the
557294294Sgnn		 * number of buffers if merged rx bufs were negotiated.
558294294Sgnn		 */
559294294Sgnn		memset(vrx, 0, sc->rx_vhdrlen);
560294294Sgnn
561294294Sgnn		if (sc->rx_merge) {
562294294Sgnn			struct virtio_net_rxhdr *vrxh;
563294294Sgnn
564294294Sgnn			vrxh = vrx;
565294294Sgnn			vrxh->vrh_bufs = 1;
566294294Sgnn		}
567294294Sgnn
568294294Sgnn		/*
569294294Sgnn		 * Release this chain and handle more chains.
570294294Sgnn		 */
571294294Sgnn		vq_relchain(vq, idx, len + sc->rx_vhdrlen);
572294294Sgnn	} while (vq_has_descs(vq));
573294294Sgnn
574294294Sgnn	/* Interrupt if needed, including for NOTIFY_ON_EMPTY. */
575294294Sgnn	vq_endchains(vq, 1);
576294294Sgnn}
577294294Sgnn
578294294Sgnnstatic void
579294294Sgnnpci_vtnet_rx_callback(int fd, enum ev_type type, void *param)
580294294Sgnn{
581221828Sgrehan	struct pci_vtnet_softc *sc = param;
582221828Sgrehan
583250083Sneel	pthread_mutex_lock(&sc->rx_mtx);
584250083Sneel	sc->rx_in_progress = 1;
585294294Sgnn	sc->pci_vtnet_rx(sc);
586250083Sneel	sc->rx_in_progress = 0;
587250083Sneel	pthread_mutex_unlock(&sc->rx_mtx);
588221828Sgrehan
589221828Sgrehan}
590221828Sgrehan
591221828Sgrehanstatic void
592253440Sgrehanpci_vtnet_ping_rxq(void *vsc, struct vqueue_info *vq)
593221828Sgrehan{
594253440Sgrehan	struct pci_vtnet_softc *sc = vsc;
595253440Sgrehan
596221828Sgrehan	/*
597221828Sgrehan	 * A qnotify means that the rx process can now begin
598221828Sgrehan	 */
599221828Sgrehan	if (sc->vsc_rx_ready == 0) {
600221828Sgrehan		sc->vsc_rx_ready = 1;
601282839Smav		vq->vq_used->vu_flags |= VRING_USED_F_NO_NOTIFY;
602221828Sgrehan	}
603221828Sgrehan}
604221828Sgrehan
605221828Sgrehanstatic void
606253440Sgrehanpci_vtnet_proctx(struct pci_vtnet_softc *sc, struct vqueue_info *vq)
607221828Sgrehan{
608221828Sgrehan	struct iovec iov[VTNET_MAXSEGS + 1];
609253440Sgrehan	int i, n;
610253440Sgrehan	int plen, tlen;
611280743Smav	uint16_t idx;
612221828Sgrehan
613221828Sgrehan	/*
614253440Sgrehan	 * Obtain chain of descriptors.  The first one is
615253440Sgrehan	 * really the header descriptor, so we need to sum
616253440Sgrehan	 * up two lengths: packet length and transfer length.
617221828Sgrehan	 */
618280743Smav	n = vq_getchain(vq, &idx, iov, VTNET_MAXSEGS, NULL);
619253440Sgrehan	assert(n >= 1 && n <= VTNET_MAXSEGS);
620253440Sgrehan	plen = 0;
621253440Sgrehan	tlen = iov[0].iov_len;
622253440Sgrehan	for (i = 1; i < n; i++) {
623253440Sgrehan		plen += iov[i].iov_len;
624253440Sgrehan		tlen += iov[i].iov_len;
625221828Sgrehan	}
626221828Sgrehan
627253440Sgrehan	DPRINTF(("virtio: packet send, %d bytes, %d segs\n\r", plen, n));
628294294Sgnn	sc->pci_vtnet_tx(sc, &iov[1], n - 1, plen);
629221828Sgrehan
630253440Sgrehan	/* chain is processed, release it and set tlen */
631280743Smav	vq_relchain(vq, idx, tlen);
632221828Sgrehan}
633221828Sgrehan
634221828Sgrehanstatic void
635253440Sgrehanpci_vtnet_ping_txq(void *vsc, struct vqueue_info *vq)
636221828Sgrehan{
637253440Sgrehan	struct pci_vtnet_softc *sc = vsc;
638221828Sgrehan
639221828Sgrehan	/*
640253440Sgrehan	 * Any ring entries to process?
641221828Sgrehan	 */
642253440Sgrehan	if (!vq_has_descs(vq))
643221828Sgrehan		return;
644221828Sgrehan
645249917Sgrehan	/* Signal the tx thread for processing */
646249917Sgrehan	pthread_mutex_lock(&sc->tx_mtx);
647282839Smav	vq->vq_used->vu_flags |= VRING_USED_F_NO_NOTIFY;
648249917Sgrehan	if (sc->tx_in_progress == 0)
649249917Sgrehan		pthread_cond_signal(&sc->tx_cond);
650249917Sgrehan	pthread_mutex_unlock(&sc->tx_mtx);
651221828Sgrehan}
652221828Sgrehan
653249917Sgrehan/*
654249917Sgrehan * Thread which will handle processing of TX desc
655249917Sgrehan */
656249917Sgrehanstatic void *
657249917Sgrehanpci_vtnet_tx_thread(void *param)
658249917Sgrehan{
659253440Sgrehan	struct pci_vtnet_softc *sc = param;
660253440Sgrehan	struct vqueue_info *vq;
661282839Smav	int error;
662253440Sgrehan
663253440Sgrehan	vq = &sc->vsc_queues[VTNET_TXQ];
664253440Sgrehan
665253440Sgrehan	/*
666253440Sgrehan	 * Let us wait till the tx queue pointers get initialised &
667253440Sgrehan	 * first tx signaled
668249917Sgrehan	 */
669249917Sgrehan	pthread_mutex_lock(&sc->tx_mtx);
670249917Sgrehan	error = pthread_cond_wait(&sc->tx_cond, &sc->tx_mtx);
671249917Sgrehan	assert(error == 0);
672253440Sgrehan
673249917Sgrehan	for (;;) {
674253440Sgrehan		/* note - tx mutex is locked here */
675282839Smav		while (sc->resetting || !vq_has_descs(vq)) {
676282839Smav			vq->vq_used->vu_flags &= ~VRING_USED_F_NO_NOTIFY;
677282839Smav			mb();
678282839Smav			if (!sc->resetting && vq_has_descs(vq))
679282839Smav				break;
680250197Sneel
681282839Smav			sc->tx_in_progress = 0;
682282839Smav			error = pthread_cond_wait(&sc->tx_cond, &sc->tx_mtx);
683282839Smav			assert(error == 0);
684282839Smav		}
685282839Smav		vq->vq_used->vu_flags |= VRING_USED_F_NO_NOTIFY;
686249917Sgrehan		sc->tx_in_progress = 1;
687249917Sgrehan		pthread_mutex_unlock(&sc->tx_mtx);
688249917Sgrehan
689253440Sgrehan		do {
690249917Sgrehan			/*
691253440Sgrehan			 * Run through entries, placing them into
692253440Sgrehan			 * iovecs and sending when an end-of-packet
693253440Sgrehan			 * is found
694249917Sgrehan			 */
695253440Sgrehan			pci_vtnet_proctx(sc, vq);
696253440Sgrehan		} while (vq_has_descs(vq));
697250197Sneel
698250197Sneel		/*
699250197Sneel		 * Generate an interrupt if needed.
700250197Sneel		 */
701253440Sgrehan		vq_endchains(vq, 1);
702253440Sgrehan
703253440Sgrehan		pthread_mutex_lock(&sc->tx_mtx);
704249917Sgrehan	}
705221828Sgrehan}
706221828Sgrehan
707253440Sgrehan#ifdef notyet
708221828Sgrehanstatic void
709253440Sgrehanpci_vtnet_ping_ctlq(void *vsc, struct vqueue_info *vq)
710221828Sgrehan{
711221828Sgrehan
712253440Sgrehan	DPRINTF(("vtnet: control qnotify!\n\r"));
713221828Sgrehan}
714253440Sgrehan#endif
715221828Sgrehan
716221828Sgrehanstatic int
717252682Sgrehanpci_vtnet_parsemac(char *mac_str, uint8_t *mac_addr)
718252682Sgrehan{
719252682Sgrehan        struct ether_addr *ea;
720252682Sgrehan        char *tmpstr;
721252682Sgrehan        char zero_addr[ETHER_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 };
722252682Sgrehan
723252682Sgrehan        tmpstr = strsep(&mac_str,"=");
724252682Sgrehan
725252682Sgrehan        if ((mac_str != NULL) && (!strcmp(tmpstr,"mac"))) {
726252682Sgrehan                ea = ether_aton(mac_str);
727252682Sgrehan
728252682Sgrehan                if (ea == NULL || ETHER_IS_MULTICAST(ea->octet) ||
729252682Sgrehan                    memcmp(ea->octet, zero_addr, ETHER_ADDR_LEN) == 0) {
730252682Sgrehan			fprintf(stderr, "Invalid MAC %s\n", mac_str);
731252682Sgrehan                        return (EINVAL);
732252682Sgrehan                } else
733252682Sgrehan                        memcpy(mac_addr, ea->octet, ETHER_ADDR_LEN);
734252682Sgrehan        }
735252682Sgrehan
736252682Sgrehan        return (0);
737252682Sgrehan}
738252682Sgrehan
739294294Sgnnstatic void
740294294Sgnnpci_vtnet_tap_setup(struct pci_vtnet_softc *sc, char *devname)
741294294Sgnn{
742294294Sgnn	char tbuf[80];
743252682Sgrehan
744294294Sgnn	strcpy(tbuf, "/dev/");
745294294Sgnn	strlcat(tbuf, devname, sizeof(tbuf));
746294294Sgnn
747294294Sgnn	sc->pci_vtnet_rx = pci_vtnet_tap_rx;
748294294Sgnn	sc->pci_vtnet_tx = pci_vtnet_tap_tx;
749294294Sgnn
750294294Sgnn	sc->vsc_tapfd = open(tbuf, O_RDWR);
751294294Sgnn	if (sc->vsc_tapfd == -1) {
752294294Sgnn		WPRINTF(("open of tap device %s failed\n", tbuf));
753294294Sgnn		return;
754294294Sgnn	}
755294294Sgnn
756294294Sgnn	/*
757294294Sgnn	 * Set non-blocking and register for read
758294294Sgnn	 * notifications with the event loop
759294294Sgnn	 */
760294294Sgnn	int opt = 1;
761294294Sgnn	if (ioctl(sc->vsc_tapfd, FIONBIO, &opt) < 0) {
762294294Sgnn		WPRINTF(("tap device O_NONBLOCK failed\n"));
763294294Sgnn		close(sc->vsc_tapfd);
764294294Sgnn		sc->vsc_tapfd = -1;
765294294Sgnn	}
766294294Sgnn
767294294Sgnn	sc->vsc_mevp = mevent_add(sc->vsc_tapfd,
768294294Sgnn				  EVF_READ,
769294294Sgnn				  pci_vtnet_rx_callback,
770294294Sgnn				  sc);
771294294Sgnn	if (sc->vsc_mevp == NULL) {
772294294Sgnn		WPRINTF(("Could not register event\n"));
773294294Sgnn		close(sc->vsc_tapfd);
774294294Sgnn		sc->vsc_tapfd = -1;
775294294Sgnn	}
776294294Sgnn}
777294294Sgnn
778294294Sgnnstatic void
779294294Sgnnpci_vtnet_netmap_setup(struct pci_vtnet_softc *sc, char *ifname)
780294294Sgnn{
781294294Sgnn	sc->pci_vtnet_rx = pci_vtnet_netmap_rx;
782294294Sgnn	sc->pci_vtnet_tx = pci_vtnet_netmap_tx;
783294294Sgnn
784294294Sgnn	sc->vsc_nmd = nm_open(ifname, NULL, 0, 0);
785294294Sgnn	if (sc->vsc_nmd == NULL) {
786294294Sgnn		WPRINTF(("open of netmap device %s failed\n", ifname));
787294294Sgnn		return;
788294294Sgnn	}
789294294Sgnn
790294294Sgnn	sc->vsc_mevp = mevent_add(sc->vsc_nmd->fd,
791294294Sgnn				  EVF_READ,
792294294Sgnn				  pci_vtnet_rx_callback,
793294294Sgnn				  sc);
794294294Sgnn	if (sc->vsc_mevp == NULL) {
795294294Sgnn		WPRINTF(("Could not register event\n"));
796294294Sgnn		nm_close(sc->vsc_nmd);
797294294Sgnn		sc->vsc_nmd = NULL;
798294294Sgnn	}
799294294Sgnn}
800294294Sgnn
801252682Sgrehanstatic int
802221828Sgrehanpci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
803221828Sgrehan{
804221828Sgrehan	MD5_CTX mdctx;
805221828Sgrehan	unsigned char digest[16];
806221828Sgrehan	char nstr[80];
807249917Sgrehan	char tname[MAXCOMLEN + 1];
808221828Sgrehan	struct pci_vtnet_softc *sc;
809252682Sgrehan	char *devname;
810252682Sgrehan	char *vtopts;
811252682Sgrehan	int mac_provided;
812221828Sgrehan
813268953Sjhb	sc = calloc(1, sizeof(struct pci_vtnet_softc));
814221828Sgrehan
815253440Sgrehan	pthread_mutex_init(&sc->vsc_mtx, NULL);
816221828Sgrehan
817253440Sgrehan	vi_softc_linkup(&sc->vsc_vs, &vtnet_vi_consts, sc, pi, sc->vsc_queues);
818267393Sjhb	sc->vsc_vs.vs_mtx = &sc->vsc_mtx;
819267393Sjhb
820253440Sgrehan	sc->vsc_queues[VTNET_RXQ].vq_qsize = VTNET_RINGSZ;
821253440Sgrehan	sc->vsc_queues[VTNET_RXQ].vq_notify = pci_vtnet_ping_rxq;
822253440Sgrehan	sc->vsc_queues[VTNET_TXQ].vq_qsize = VTNET_RINGSZ;
823253440Sgrehan	sc->vsc_queues[VTNET_TXQ].vq_notify = pci_vtnet_ping_txq;
824253440Sgrehan#ifdef notyet
825253440Sgrehan	sc->vsc_queues[VTNET_CTLQ].vq_qsize = VTNET_RINGSZ;
826253440Sgrehan        sc->vsc_queues[VTNET_CTLQ].vq_notify = pci_vtnet_ping_ctlq;
827253440Sgrehan#endif
828246109Sneel
829246109Sneel	/*
830252682Sgrehan	 * Attempt to open the tap device and read the MAC address
831252682Sgrehan	 * if specified
832221828Sgrehan	 */
833252682Sgrehan	mac_provided = 0;
834221828Sgrehan	sc->vsc_tapfd = -1;
835294294Sgnn	sc->vsc_nmd = NULL;
836221828Sgrehan	if (opts != NULL) {
837252682Sgrehan		int err;
838221828Sgrehan
839252682Sgrehan		devname = vtopts = strdup(opts);
840252682Sgrehan		(void) strsep(&vtopts, ",");
841252682Sgrehan
842252682Sgrehan		if (vtopts != NULL) {
843253440Sgrehan			err = pci_vtnet_parsemac(vtopts, sc->vsc_config.mac);
844252682Sgrehan			if (err != 0) {
845252682Sgrehan				free(devname);
846252682Sgrehan				return (err);
847252682Sgrehan			}
848252682Sgrehan			mac_provided = 1;
849252682Sgrehan		}
850252682Sgrehan
851294294Sgnn		if (strncmp(devname, "vale", 4) == 0)
852294294Sgnn			pci_vtnet_netmap_setup(sc, devname);
853294294Sgnn		if ((strncmp(devname, "tap", 3) == 0) ||
854307183Snp		    (strncmp(devname, "vmnet", 5) == 0))
855294294Sgnn			pci_vtnet_tap_setup(sc, devname);
856221828Sgrehan
857252682Sgrehan		free(devname);
858221828Sgrehan	}
859221828Sgrehan
860221828Sgrehan	/*
861252682Sgrehan	 * The default MAC address is the standard NetApp OUI of 00-a0-98,
862252682Sgrehan	 * followed by an MD5 of the PCI slot/func number and dev name
863221828Sgrehan	 */
864252682Sgrehan	if (!mac_provided) {
865244159Sgrehan		snprintf(nstr, sizeof(nstr), "%d-%d-%s", pi->pi_slot,
866259301Sgrehan		    pi->pi_func, vmname);
867221828Sgrehan
868252682Sgrehan		MD5Init(&mdctx);
869252682Sgrehan		MD5Update(&mdctx, nstr, strlen(nstr));
870252682Sgrehan		MD5Final(digest, &mdctx);
871221828Sgrehan
872253440Sgrehan		sc->vsc_config.mac[0] = 0x00;
873253440Sgrehan		sc->vsc_config.mac[1] = 0xa0;
874253440Sgrehan		sc->vsc_config.mac[2] = 0x98;
875253440Sgrehan		sc->vsc_config.mac[3] = digest[0];
876253440Sgrehan		sc->vsc_config.mac[4] = digest[1];
877253440Sgrehan		sc->vsc_config.mac[5] = digest[2];
878252682Sgrehan	}
879221828Sgrehan
880221828Sgrehan	/* initialize config space */
881221828Sgrehan	pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET);
882221828Sgrehan	pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
883221828Sgrehan	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK);
884221828Sgrehan	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET);
885284900Sneel	pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR);
886253440Sgrehan
887282840Smav	/* Link is up if we managed to open tap device. */
888282840Smav	sc->vsc_config.status = (opts == NULL || sc->vsc_tapfd >= 0);
889246109Sneel
890253440Sgrehan	/* use BAR 1 to map MSI-X table and PBA, if we're using MSI-X */
891256755Sgrehan	if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix()))
892253440Sgrehan		return (1);
893246109Sneel
894253440Sgrehan	/* use BAR 0 to map config regs in IO space */
895253440Sgrehan	vi_set_io_bar(&sc->vsc_vs, 0);
896246109Sneel
897250083Sneel	sc->resetting = 0;
898250083Sneel
899271685Sgrehan	sc->rx_merge = 1;
900271685Sgrehan	sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr);
901250083Sneel	sc->rx_in_progress = 0;
902250083Sneel	pthread_mutex_init(&sc->rx_mtx, NULL);
903250083Sneel
904249917Sgrehan	/*
905253440Sgrehan	 * Initialize tx semaphore & spawn TX processing thread.
906249917Sgrehan	 * As of now, only one thread for TX desc processing is
907249917Sgrehan	 * spawned.
908249917Sgrehan	 */
909249917Sgrehan	sc->tx_in_progress = 0;
910249917Sgrehan	pthread_mutex_init(&sc->tx_mtx, NULL);
911249917Sgrehan	pthread_cond_init(&sc->tx_cond, NULL);
912249917Sgrehan	pthread_create(&sc->tx_tid, NULL, pci_vtnet_tx_thread, (void *)sc);
913259301Sgrehan	snprintf(tname, sizeof(tname), "vtnet-%d:%d tx", pi->pi_slot,
914259301Sgrehan	    pi->pi_func);
915249917Sgrehan        pthread_set_name_np(sc->tx_tid, tname);
916221828Sgrehan
917221828Sgrehan	return (0);
918221828Sgrehan}
919221828Sgrehan
920253440Sgrehanstatic int
921253440Sgrehanpci_vtnet_cfgwrite(void *vsc, int offset, int size, uint32_t value)
922246109Sneel{
923253440Sgrehan	struct pci_vtnet_softc *sc = vsc;
924222830Sgrehan	void *ptr;
925222830Sgrehan
926253440Sgrehan	if (offset < 6) {
927253440Sgrehan		assert(offset + size <= 6);
928221828Sgrehan		/*
929221828Sgrehan		 * The driver is allowed to change the MAC address
930221828Sgrehan		 */
931253440Sgrehan		ptr = &sc->vsc_config.mac[offset];
932253440Sgrehan		memcpy(ptr, &value, size);
933253440Sgrehan	} else {
934271685Sgrehan		/* silently ignore other writes */
935253440Sgrehan		DPRINTF(("vtnet: write to readonly reg %d\n\r", offset));
936221828Sgrehan	}
937271685Sgrehan
938253440Sgrehan	return (0);
939221828Sgrehan}
940221828Sgrehan
941253440Sgrehanstatic int
942253440Sgrehanpci_vtnet_cfgread(void *vsc, int offset, int size, uint32_t *retval)
943221828Sgrehan{
944253440Sgrehan	struct pci_vtnet_softc *sc = vsc;
945222830Sgrehan	void *ptr;
946221828Sgrehan
947253440Sgrehan	ptr = (uint8_t *)&sc->vsc_config + offset;
948253440Sgrehan	memcpy(retval, ptr, size);
949253440Sgrehan	return (0);
950221828Sgrehan}
951221828Sgrehan
952271685Sgrehanstatic void
953271685Sgrehanpci_vtnet_neg_features(void *vsc, uint64_t negotiated_features)
954271685Sgrehan{
955271685Sgrehan	struct pci_vtnet_softc *sc = vsc;
956271685Sgrehan
957271685Sgrehan	sc->vsc_features = negotiated_features;
958271685Sgrehan
959271685Sgrehan	if (!(sc->vsc_features & VIRTIO_NET_F_MRG_RXBUF)) {
960271685Sgrehan		sc->rx_merge = 0;
961271685Sgrehan		/* non-merge rx header is 2 bytes shorter */
962271685Sgrehan		sc->rx_vhdrlen -= 2;
963271685Sgrehan	}
964271685Sgrehan}
965271685Sgrehan
966221828Sgrehanstruct pci_devemu pci_de_vnet = {
967241744Sgrehan	.pe_emu = 	"virtio-net",
968241744Sgrehan	.pe_init =	pci_vtnet_init,
969253440Sgrehan	.pe_barwrite =	vi_pci_write,
970253440Sgrehan	.pe_barread =	vi_pci_read
971221828Sgrehan};
972221828SgrehanPCI_EMUL_SET(pci_de_vnet);
973