pci_virtio_net.c revision 247523
1/*-
2 * Copyright (c) 2011 NetApp, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/usr.sbin/bhyve/pci_virtio_net.c 247523 2013-03-01 02:26:28Z neel $
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/usr.sbin/bhyve/pci_virtio_net.c 247523 2013-03-01 02:26:28Z neel $");
31
32#include <sys/param.h>
33#include <sys/linker_set.h>
34#include <sys/select.h>
35#include <sys/uio.h>
36#include <sys/ioctl.h>
37
38#include <errno.h>
39#include <fcntl.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <stdint.h>
43#include <string.h>
44#include <strings.h>
45#include <unistd.h>
46#include <assert.h>
47#include <md5.h>
48#include <pthread.h>
49
50#include "bhyverun.h"
51#include "pci_emul.h"
52#include "mevent.h"
53#include "virtio.h"
54
55#define VTNET_RINGSZ	256
56
57#define VTNET_MAXSEGS	32
58
59/*
60 * PCI config-space register offsets
61 */
62#define VTNET_R_CFG0	24
63#define VTNET_R_CFG1	25
64#define VTNET_R_CFG2	26
65#define VTNET_R_CFG3	27
66#define VTNET_R_CFG4	28
67#define VTNET_R_CFG5	29
68#define VTNET_R_CFG6	30
69#define VTNET_R_CFG7	31
70#define VTNET_R_MAX	31
71
72#define VTNET_REGSZ	VTNET_R_MAX+1
73
74/*
75 * Host capabilities
76 */
77#define VTNET_S_HOSTCAPS      \
78  ( 0x00000020 |	/* host supplies MAC */ \
79    0x00008000 |	/* host can merge Rx buffers */ \
80    0x00010000 )	/* config status available */
81
82/*
83 * Queue definitions.
84 */
85#define VTNET_RXQ	0
86#define VTNET_TXQ	1
87#define VTNET_CTLQ	2
88
89#define VTNET_MAXQ	3
90
91static int use_msix = 1;
92
93struct vring_hqueue {
94	/* Internal state */
95	uint16_t	hq_size;
96	uint16_t	hq_cur_aidx;		/* trails behind 'avail_idx' */
97
98	 /* Host-context pointers to the queue */
99	struct virtio_desc *hq_dtable;
100	uint16_t	*hq_avail_flags;
101	uint16_t	*hq_avail_idx;		/* monotonically increasing */
102	uint16_t	*hq_avail_ring;
103
104	uint16_t	*hq_used_flags;
105	uint16_t	*hq_used_idx;		/* monotonically increasing */
106	struct virtio_used *hq_used_ring;
107};
108
109/*
110 * Fixed network header size
111 */
112struct virtio_net_rxhdr {
113	uint8_t		vrh_flags;
114	uint8_t		vrh_gso_type;
115	uint16_t	vrh_hdr_len;
116	uint16_t	vrh_gso_size;
117	uint16_t	vrh_csum_start;
118	uint16_t	vrh_csum_offset;
119	uint16_t	vrh_bufs;
120} __packed;
121
122/*
123 * Debug printf
124 */
125static int pci_vtnet_debug;
126#define DPRINTF(params) if (pci_vtnet_debug) printf params
127#define WPRINTF(params) printf params
128
129/*
130 * Per-device softc
131 */
132struct pci_vtnet_softc {
133	struct pci_devinst *vsc_pi;
134	pthread_mutex_t vsc_mtx;
135	struct mevent	*vsc_mevp;
136
137	int		vsc_curq;
138	int		vsc_status;
139	int		vsc_isr;
140	int		vsc_tapfd;
141	int		vsc_rx_ready;
142	int		vsc_rxpend;
143
144	uint32_t	vsc_features;
145	uint8_t		vsc_macaddr[6];
146
147	uint64_t	vsc_pfn[VTNET_MAXQ];
148	struct	vring_hqueue vsc_hq[VTNET_MAXQ];
149	uint16_t	vsc_msix_table_idx[VTNET_MAXQ];
150};
151
152/*
153 * Return the size of IO BAR that maps virtio header and device specific
154 * region. The size would vary depending on whether MSI-X is enabled or
155 * not.
156 */
157static uint64_t
158pci_vtnet_iosize(struct pci_devinst *pi)
159{
160	if (pci_msix_enabled(pi))
161		return (VTNET_REGSZ);
162	else
163		return (VTNET_REGSZ - (VTCFG_R_CFG1 - VTCFG_R_MSIX));
164}
165
166/*
167 * Return the number of available descriptors in the vring taking care
168 * of the 16-bit index wraparound.
169 */
170static int
171hq_num_avail(struct vring_hqueue *hq)
172{
173	int ndesc;
174
175	if (*hq->hq_avail_idx >= hq->hq_cur_aidx)
176		ndesc = *hq->hq_avail_idx - hq->hq_cur_aidx;
177	else
178		ndesc = UINT16_MAX - hq->hq_cur_aidx + *hq->hq_avail_idx + 1;
179
180	assert(ndesc >= 0 && ndesc <= hq->hq_size);
181
182	return (ndesc);
183}
184
185static uint16_t
186pci_vtnet_qsize(int qnum)
187{
188	/* XXX no ctl queue currently */
189	if (qnum == VTNET_CTLQ) {
190		return (0);
191	}
192
193	/* XXX fixed currently. Maybe different for tx/rx/ctl */
194	return (VTNET_RINGSZ);
195}
196
197static void
198pci_vtnet_ring_reset(struct pci_vtnet_softc *sc, int ring)
199{
200	struct vring_hqueue *hq;
201
202	assert(ring < VTNET_MAXQ);
203
204	hq = &sc->vsc_hq[ring];
205
206	/*
207	 * Reset all soft state
208	 */
209	hq->hq_cur_aidx = 0;
210}
211
212static void
213pci_vtnet_update_status(struct pci_vtnet_softc *sc, uint32_t value)
214{
215
216	if (value == 0) {
217		DPRINTF(("vtnet: device reset requested !\n"));
218		pci_vtnet_ring_reset(sc, VTNET_RXQ);
219		pci_vtnet_ring_reset(sc, VTNET_TXQ);
220		sc->vsc_rx_ready = 0;
221	}
222
223	sc->vsc_status = value;
224}
225
226/*
227 * Called to send a buffer chain out to the tap device
228 */
229static void
230pci_vtnet_tap_tx(struct pci_vtnet_softc *sc, struct iovec *iov, int iovcnt,
231		 int len)
232{
233	char pad[60];
234
235	if (sc->vsc_tapfd == -1)
236		return;
237
238	/*
239	 * If the length is < 60, pad out to that and add the
240	 * extra zero'd segment to the iov. It is guaranteed that
241	 * there is always an extra iov available by the caller.
242	 */
243	if (len < 60) {
244		memset(pad, 0, 60 - len);
245		iov[iovcnt].iov_base = pad;
246		iov[iovcnt].iov_len = 60 - len;
247		iovcnt++;
248	}
249	(void) writev(sc->vsc_tapfd, iov, iovcnt);
250}
251
252/*
253 *  Called when there is read activity on the tap file descriptor.
254 * Each buffer posted by the guest is assumed to be able to contain
255 * an entire ethernet frame + rx header.
256 *  MP note: the dummybuf is only used for discarding frames, so there
257 * is no need for it to be per-vtnet or locked.
258 */
259static uint8_t dummybuf[2048];
260
261static void
262pci_vtnet_tap_rx(struct pci_vtnet_softc *sc)
263{
264	struct virtio_desc *vd;
265	struct virtio_used *vu;
266	struct vring_hqueue *hq;
267	struct virtio_net_rxhdr *vrx;
268	uint8_t *buf;
269	int i;
270	int len;
271	int ndescs;
272	int didx, uidx, aidx;	/* descriptor, avail and used index */
273
274	/*
275	 * Should never be called without a valid tap fd
276	 */
277	assert(sc->vsc_tapfd != -1);
278
279	/*
280	 * But, will be called when the rx ring hasn't yet
281	 * been set up.
282	 */
283	if (sc->vsc_rx_ready == 0) {
284		/*
285		 * Drop the packet and try later.
286		 */
287		(void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf));
288		return;
289	}
290
291	/*
292	 * Calculate the number of available rx buffers
293	 */
294	hq = &sc->vsc_hq[VTNET_RXQ];
295
296	ndescs = hq_num_avail(hq);
297
298	if (ndescs == 0) {
299		/*
300		 * Need to wait for host notification to read
301		 */
302		if (sc->vsc_rxpend == 0) {
303			WPRINTF(("vtnet: no rx descriptors !\n"));
304			sc->vsc_rxpend = 1;
305		}
306
307		/*
308		 * Drop the packet and try later
309		 */
310		(void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf));
311		return;
312	}
313
314	aidx = hq->hq_cur_aidx;
315	uidx = *hq->hq_used_idx;
316	for (i = 0; i < ndescs; i++) {
317		/*
318		 * 'aidx' indexes into the an array of descriptor indexes
319		 */
320		didx = hq->hq_avail_ring[aidx % hq->hq_size];
321		assert(didx >= 0 && didx < hq->hq_size);
322
323		vd = &hq->hq_dtable[didx];
324
325		/*
326		 * Get a pointer to the rx header, and use the
327		 * data immediately following it for the packet buffer.
328		 */
329		vrx = paddr_guest2host(vd->vd_addr, vd->vd_len);
330		buf = (uint8_t *)(vrx + 1);
331
332		len = read(sc->vsc_tapfd, buf,
333			   vd->vd_len - sizeof(struct virtio_net_rxhdr));
334
335		if (len < 0 && errno == EWOULDBLOCK) {
336			break;
337		}
338
339		/*
340		 * The only valid field in the rx packet header is the
341		 * number of buffers, which is always 1 without TSO
342		 * support.
343		 */
344		memset(vrx, 0, sizeof(struct virtio_net_rxhdr));
345		vrx->vrh_bufs = 1;
346
347		/*
348		 * Write this descriptor into the used ring
349		 */
350		vu = &hq->hq_used_ring[uidx % hq->hq_size];
351		vu->vu_idx = didx;
352		vu->vu_tlen = len + sizeof(struct virtio_net_rxhdr);
353		uidx++;
354		aidx++;
355	}
356
357	/*
358	 * Update the used pointer, and signal an interrupt if allowed
359	 */
360	*hq->hq_used_idx = uidx;
361	hq->hq_cur_aidx = aidx;
362
363	if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) {
364		if (use_msix) {
365			pci_generate_msix(sc->vsc_pi,
366					  sc->vsc_msix_table_idx[VTNET_RXQ]);
367		} else {
368			sc->vsc_isr |= 1;
369			pci_generate_msi(sc->vsc_pi, 0);
370		}
371	}
372}
373
374static void
375pci_vtnet_tap_callback(int fd, enum ev_type type, void *param)
376{
377	struct pci_vtnet_softc *sc = param;
378
379	pthread_mutex_lock(&sc->vsc_mtx);
380	pci_vtnet_tap_rx(sc);
381	pthread_mutex_unlock(&sc->vsc_mtx);
382
383}
384
385static void
386pci_vtnet_ping_rxq(struct pci_vtnet_softc *sc)
387{
388	/*
389	 * A qnotify means that the rx process can now begin
390	 */
391	if (sc->vsc_rx_ready == 0) {
392		sc->vsc_rx_ready = 1;
393	}
394
395	/*
396	 * If the rx queue was empty, attempt to receive a
397	 * packet that was previously blocked due to no rx bufs
398	 * available
399	 */
400	if (sc->vsc_rxpend) {
401		WPRINTF(("vtnet: rx resumed\n\r"));
402		sc->vsc_rxpend = 0;
403		pci_vtnet_tap_rx(sc);
404	}
405}
406
407static void
408pci_vtnet_proctx(struct pci_vtnet_softc *sc, struct vring_hqueue *hq)
409{
410	struct iovec iov[VTNET_MAXSEGS + 1];
411	struct virtio_desc *vd;
412	struct virtio_used *vu;
413	int i;
414	int plen;
415	int tlen;
416	int uidx, aidx, didx;
417
418	uidx = *hq->hq_used_idx;
419	aidx = hq->hq_cur_aidx;
420	didx = hq->hq_avail_ring[aidx % hq->hq_size];
421	assert(didx >= 0 && didx < hq->hq_size);
422
423	vd = &hq->hq_dtable[didx];
424
425	/*
426	 * Run through the chain of descriptors, ignoring the
427	 * first header descriptor. However, include the header
428	 * length in the total length that will be put into the
429	 * used queue.
430	 */
431	tlen = vd->vd_len;
432	vd = &hq->hq_dtable[vd->vd_next];
433
434	for (i = 0, plen = 0;
435	     i < VTNET_MAXSEGS;
436	     i++, vd = &hq->hq_dtable[vd->vd_next]) {
437		iov[i].iov_base = paddr_guest2host(vd->vd_addr, vd->vd_len);
438		iov[i].iov_len = vd->vd_len;
439		plen += vd->vd_len;
440		tlen += vd->vd_len;
441
442		if ((vd->vd_flags & VRING_DESC_F_NEXT) == 0)
443			break;
444	}
445	assert(i < VTNET_MAXSEGS);
446
447	DPRINTF(("virtio: packet send, %d bytes, %d segs\n\r", plen, i + 1));
448	pci_vtnet_tap_tx(sc, iov, i + 1, plen);
449
450	/*
451	 * Return this chain back to the host
452	 */
453	vu = &hq->hq_used_ring[uidx % hq->hq_size];
454	vu->vu_idx = didx;
455	vu->vu_tlen = tlen;
456	hq->hq_cur_aidx = aidx + 1;
457	*hq->hq_used_idx = uidx + 1;
458
459	/*
460	 * Generate an interrupt if able
461	 */
462	if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) {
463		if (use_msix) {
464			pci_generate_msix(sc->vsc_pi,
465					  sc->vsc_msix_table_idx[VTNET_TXQ]);
466		} else {
467			sc->vsc_isr |= 1;
468			pci_generate_msi(sc->vsc_pi, 0);
469		}
470	}
471}
472
473static void
474pci_vtnet_ping_txq(struct pci_vtnet_softc *sc)
475{
476	struct vring_hqueue *hq = &sc->vsc_hq[VTNET_TXQ];
477	int i;
478	int ndescs;
479
480	/*
481	 * Calculate number of ring entries to process
482	 */
483	ndescs = hq_num_avail(hq);
484
485	if (ndescs == 0)
486		return;
487
488	/*
489	 * Run through all the entries, placing them into iovecs and
490	 * sending when an end-of-packet is found
491	 */
492	for (i = 0; i < ndescs; i++)
493		pci_vtnet_proctx(sc, hq);
494}
495
496static void
497pci_vtnet_ping_ctlq(struct pci_vtnet_softc *sc)
498{
499
500	DPRINTF(("vtnet: control qnotify!\n\r"));
501}
502
503static void
504pci_vtnet_ring_init(struct pci_vtnet_softc *sc, uint64_t pfn)
505{
506	struct vring_hqueue *hq;
507	int qnum = sc->vsc_curq;
508
509	assert(qnum < VTNET_MAXQ);
510
511	sc->vsc_pfn[qnum] = pfn << VRING_PFN;
512
513	/*
514	 * Set up host pointers to the various parts of the
515	 * queue
516	 */
517	hq = &sc->vsc_hq[qnum];
518	hq->hq_size = pci_vtnet_qsize(qnum);
519
520	hq->hq_dtable = paddr_guest2host(pfn << VRING_PFN,
521					 vring_size(hq->hq_size));
522	hq->hq_avail_flags =  (uint16_t *)(hq->hq_dtable + hq->hq_size);
523	hq->hq_avail_idx = hq->hq_avail_flags + 1;
524	hq->hq_avail_ring = hq->hq_avail_flags + 2;
525	hq->hq_used_flags = (uint16_t *)roundup2((uintptr_t)hq->hq_avail_ring,
526						 VRING_ALIGN);
527	hq->hq_used_idx = hq->hq_used_flags + 1;
528	hq->hq_used_ring = (struct virtio_used *)(hq->hq_used_flags + 2);
529
530	/*
531	 * Initialize queue indexes
532	 */
533	hq->hq_cur_aidx = 0;
534}
535
536static int
537pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
538{
539	MD5_CTX mdctx;
540	unsigned char digest[16];
541	char nstr[80];
542	struct pci_vtnet_softc *sc;
543	const char *env_msi;
544
545	sc = malloc(sizeof(struct pci_vtnet_softc));
546	memset(sc, 0, sizeof(struct pci_vtnet_softc));
547
548	pi->pi_arg = sc;
549	sc->vsc_pi = pi;
550
551	pthread_mutex_init(&sc->vsc_mtx, NULL);
552
553	/*
554	 * Use MSI if set by user
555	 */
556	if ((env_msi = getenv("BHYVE_USE_MSI")) != NULL) {
557		if (strcasecmp(env_msi, "yes") == 0)
558			use_msix = 0;
559	}
560
561	/*
562	 * Attempt to open the tap device
563	 */
564	sc->vsc_tapfd = -1;
565	if (opts != NULL) {
566		char tbuf[80];
567
568		strcpy(tbuf, "/dev/");
569		strlcat(tbuf, opts, sizeof(tbuf));
570
571		sc->vsc_tapfd = open(tbuf, O_RDWR);
572		if (sc->vsc_tapfd == -1) {
573			WPRINTF(("open of tap device %s failed\n", tbuf));
574		} else {
575			/*
576			 * Set non-blocking and register for read
577			 * notifications with the event loop
578			 */
579			int opt = 1;
580			if (ioctl(sc->vsc_tapfd, FIONBIO, &opt) < 0) {
581				WPRINTF(("tap device O_NONBLOCK failed\n"));
582				close(sc->vsc_tapfd);
583				sc->vsc_tapfd = -1;
584			}
585
586			sc->vsc_mevp = mevent_add(sc->vsc_tapfd,
587						  EVF_READ,
588						  pci_vtnet_tap_callback,
589						  sc);
590			if (sc->vsc_mevp == NULL) {
591				WPRINTF(("Could not register event\n"));
592				close(sc->vsc_tapfd);
593				sc->vsc_tapfd = -1;
594			}
595		}
596	}
597
598	/*
599	 * The MAC address is the standard NetApp OUI of 00-a0-98,
600	 * followed by an MD5 of the vm name. The slot/func number is
601	 * prepended to this for slots other than 1:0, so that
602	 * a bootloader can netboot from the equivalent of slot 1.
603	 */
604	if (pi->pi_slot == 1 && pi->pi_func == 0) {
605		strncpy(nstr, vmname, sizeof(nstr));
606	} else {
607		snprintf(nstr, sizeof(nstr), "%d-%d-%s", pi->pi_slot,
608		    pi->pi_func, vmname);
609	}
610
611	MD5Init(&mdctx);
612	MD5Update(&mdctx, nstr, strlen(nstr));
613	MD5Final(digest, &mdctx);
614
615	sc->vsc_macaddr[0] = 0x00;
616	sc->vsc_macaddr[1] = 0xa0;
617	sc->vsc_macaddr[2] = 0x98;
618	sc->vsc_macaddr[3] = digest[0];
619	sc->vsc_macaddr[4] = digest[1];
620	sc->vsc_macaddr[5] = digest[2];
621
622	/* initialize config space */
623	pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET);
624	pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
625	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK);
626	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET);
627
628	if (use_msix) {
629		/* MSI-X support */
630		int i;
631
632		for (i = 0; i < VTNET_MAXQ; i++)
633			sc->vsc_msix_table_idx[i] = VIRTIO_MSI_NO_VECTOR;
634
635		/*
636		 * BAR 1 used to map MSI-X table and PBA
637		 */
638		if (pci_emul_add_msixcap(pi, VTNET_MAXQ, 1))
639			return (1);
640	} else {
641		/* MSI support */
642		pci_emul_add_msicap(pi, 1);
643	}
644
645	pci_emul_alloc_bar(pi, 0, PCIBAR_IO, VTNET_REGSZ);
646
647	return (0);
648}
649
650/*
651 * Function pointer array to handle queue notifications
652 */
653static void (*pci_vtnet_qnotify[VTNET_MAXQ])(struct pci_vtnet_softc *) = {
654	pci_vtnet_ping_rxq,
655	pci_vtnet_ping_txq,
656	pci_vtnet_ping_ctlq
657};
658
659static uint64_t
660vtnet_adjust_offset(struct pci_devinst *pi, uint64_t offset)
661{
662	/*
663	 * Device specific offsets used by guest would change based on
664	 * whether MSI-X capability is enabled or not
665	 */
666	if (!pci_msix_enabled(pi)) {
667		if (offset >= VTCFG_R_MSIX)
668			return (offset + (VTCFG_R_CFG1 - VTCFG_R_MSIX));
669	}
670
671	return (offset);
672}
673
674static void
675pci_vtnet_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
676		int baridx, uint64_t offset, int size, uint64_t value)
677{
678	struct pci_vtnet_softc *sc = pi->pi_arg;
679	void *ptr;
680
681	if (use_msix) {
682		if (baridx == pci_msix_table_bar(pi) ||
683		    baridx == pci_msix_pba_bar(pi)) {
684			pci_emul_msix_twrite(pi, offset, size, value);
685			return;
686		}
687	}
688
689	assert(baridx == 0);
690
691	if (offset + size > pci_vtnet_iosize(pi)) {
692		DPRINTF(("vtnet_write: 2big, offset %ld size %d\n",
693			 offset, size));
694		return;
695	}
696
697	pthread_mutex_lock(&sc->vsc_mtx);
698
699	offset = vtnet_adjust_offset(pi, offset);
700
701	switch (offset) {
702	case VTCFG_R_GUESTCAP:
703		assert(size == 4);
704		sc->vsc_features = value & VTNET_S_HOSTCAPS;
705		break;
706	case VTCFG_R_PFN:
707		assert(size == 4);
708		pci_vtnet_ring_init(sc, value);
709		break;
710	case VTCFG_R_QSEL:
711		assert(size == 2);
712		assert(value < VTNET_MAXQ);
713		sc->vsc_curq = value;
714		break;
715	case VTCFG_R_QNOTIFY:
716		assert(size == 2);
717		assert(value < VTNET_MAXQ);
718		(*pci_vtnet_qnotify[value])(sc);
719		break;
720	case VTCFG_R_STATUS:
721		assert(size == 1);
722		pci_vtnet_update_status(sc, value);
723		break;
724	case VTCFG_R_CFGVEC:
725		assert(size == 2);
726		sc->vsc_msix_table_idx[VTNET_CTLQ] = value;
727		break;
728	case VTCFG_R_QVEC:
729		assert(size == 2);
730		assert(sc->vsc_curq != VTNET_CTLQ);
731		sc->vsc_msix_table_idx[sc->vsc_curq] = value;
732		break;
733	case VTNET_R_CFG0:
734	case VTNET_R_CFG1:
735	case VTNET_R_CFG2:
736	case VTNET_R_CFG3:
737	case VTNET_R_CFG4:
738	case VTNET_R_CFG5:
739		assert((size + offset) <= (VTNET_R_CFG5 + 1));
740		ptr = &sc->vsc_macaddr[offset - VTNET_R_CFG0];
741		/*
742		 * The driver is allowed to change the MAC address
743		 */
744		sc->vsc_macaddr[offset - VTNET_R_CFG0] = value;
745		if (size == 1) {
746			*(uint8_t *) ptr = value;
747		} else if (size == 2) {
748			*(uint16_t *) ptr = value;
749		} else {
750			*(uint32_t *) ptr = value;
751		}
752		break;
753	case VTCFG_R_HOSTCAP:
754	case VTCFG_R_QNUM:
755	case VTCFG_R_ISR:
756	case VTNET_R_CFG6:
757	case VTNET_R_CFG7:
758		DPRINTF(("vtnet: write to readonly reg %ld\n\r", offset));
759		break;
760	default:
761		DPRINTF(("vtnet: unknown i/o write offset %ld\n\r", offset));
762		value = 0;
763		break;
764	}
765
766	pthread_mutex_unlock(&sc->vsc_mtx);
767}
768
769uint64_t
770pci_vtnet_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
771	       int baridx, uint64_t offset, int size)
772{
773	struct pci_vtnet_softc *sc = pi->pi_arg;
774	void *ptr;
775	uint64_t value;
776
777	if (use_msix) {
778		if (baridx == pci_msix_table_bar(pi) ||
779		    baridx == pci_msix_pba_bar(pi)) {
780			return (pci_emul_msix_tread(pi, offset, size));
781		}
782	}
783
784	assert(baridx == 0);
785
786	if (offset + size > pci_vtnet_iosize(pi)) {
787		DPRINTF(("vtnet_read: 2big, offset %ld size %d\n",
788			 offset, size));
789		return (0);
790	}
791
792	pthread_mutex_lock(&sc->vsc_mtx);
793
794	offset = vtnet_adjust_offset(pi, offset);
795
796	switch (offset) {
797	case VTCFG_R_HOSTCAP:
798		assert(size == 4);
799		value = VTNET_S_HOSTCAPS;
800		break;
801	case VTCFG_R_GUESTCAP:
802		assert(size == 4);
803		value = sc->vsc_features; /* XXX never read ? */
804		break;
805	case VTCFG_R_PFN:
806		assert(size == 4);
807		value = sc->vsc_pfn[sc->vsc_curq] >> VRING_PFN;
808		break;
809	case VTCFG_R_QNUM:
810		assert(size == 2);
811		value = pci_vtnet_qsize(sc->vsc_curq);
812		break;
813	case VTCFG_R_QSEL:
814		assert(size == 2);
815		value = sc->vsc_curq;  /* XXX never read ? */
816		break;
817	case VTCFG_R_QNOTIFY:
818		assert(size == 2);
819		value = sc->vsc_curq;  /* XXX never read ? */
820		break;
821	case VTCFG_R_STATUS:
822		assert(size == 1);
823		value = sc->vsc_status;
824		break;
825	case VTCFG_R_ISR:
826		assert(size == 1);
827		value = sc->vsc_isr;
828		sc->vsc_isr = 0;     /* a read clears this flag */
829		break;
830	case VTCFG_R_CFGVEC:
831		assert(size == 2);
832		value = sc->vsc_msix_table_idx[VTNET_CTLQ];
833		break;
834	case VTCFG_R_QVEC:
835		assert(size == 2);
836		assert(sc->vsc_curq != VTNET_CTLQ);
837		value = sc->vsc_msix_table_idx[sc->vsc_curq];
838		break;
839	case VTNET_R_CFG0:
840	case VTNET_R_CFG1:
841	case VTNET_R_CFG2:
842	case VTNET_R_CFG3:
843	case VTNET_R_CFG4:
844	case VTNET_R_CFG5:
845		assert((size + offset) <= (VTNET_R_CFG5 + 1));
846		ptr = &sc->vsc_macaddr[offset - VTNET_R_CFG0];
847		if (size == 1) {
848			value = *(uint8_t *) ptr;
849		} else if (size == 2) {
850			value = *(uint16_t *) ptr;
851		} else {
852			value = *(uint32_t *) ptr;
853		}
854		break;
855	case VTNET_R_CFG6:
856		assert(size != 4);
857		value = 0x01; /* XXX link always up */
858		break;
859	case VTNET_R_CFG7:
860		assert(size == 1);
861		value = 0; /* XXX link status in LSB */
862		break;
863	default:
864		DPRINTF(("vtnet: unknown i/o read offset %ld\n\r", offset));
865		value = 0;
866		break;
867	}
868
869	pthread_mutex_unlock(&sc->vsc_mtx);
870
871	return (value);
872}
873
874struct pci_devemu pci_de_vnet = {
875	.pe_emu = 	"virtio-net",
876	.pe_init =	pci_vtnet_init,
877	.pe_barwrite =	pci_vtnet_write,
878	.pe_barread =	pci_vtnet_read
879};
880PCI_EMUL_SET(pci_de_vnet);
881