pci_virtio_net.c revision 245652
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$
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
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	       20
63#define VTNET_R_CFG1	       21
64#define VTNET_R_CFG2	       22
65#define VTNET_R_CFG3	       23
66#define VTNET_R_CFG4	       24
67#define VTNET_R_CFG5	       25
68#define VTNET_R_CFG6	       26
69#define VTNET_R_CFG7	       27
70#define VTNET_R_MAX	       27
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
91struct vring_hqueue {
92	/* Internal state */
93	uint16_t	hq_size;
94	uint16_t	hq_cur_aidx;		/* trails behind 'avail_idx' */
95
96	 /* Host-context pointers to the queue */
97	struct virtio_desc *hq_dtable;
98	uint16_t	*hq_avail_flags;
99	uint16_t	*hq_avail_idx;		/* monotonically increasing */
100	uint16_t	*hq_avail_ring;
101
102	uint16_t	*hq_used_flags;
103	uint16_t	*hq_used_idx;		/* monotonically increasing */
104	struct virtio_used *hq_used_ring;
105};
106
107/*
108 * Fixed network header size
109 */
110struct virtio_net_rxhdr {
111	uint8_t		vrh_flags;
112	uint8_t		vrh_gso_type;
113	uint16_t	vrh_hdr_len;
114	uint16_t	vrh_gso_size;
115	uint16_t	vrh_csum_start;
116	uint16_t	vrh_csum_offset;
117	uint16_t	vrh_bufs;
118} __packed;
119
120/*
121 * Debug printf
122 */
123static int pci_vtnet_debug;
124#define DPRINTF(params) if (pci_vtnet_debug) printf params
125#define WPRINTF(params) printf params
126
127/*
128 * Per-device softc
129 */
130struct pci_vtnet_softc {
131	struct pci_devinst *vsc_pi;
132	pthread_mutex_t vsc_mtx;
133	struct mevent	*vsc_mevp;
134
135	int		vsc_curq;
136	int		vsc_status;
137	int		vsc_isr;
138	int		vsc_tapfd;
139	int		vsc_rx_ready;
140	int		vsc_rxpend;
141
142	uint32_t	vsc_features;
143	uint8_t		vsc_macaddr[6];
144
145	uint64_t	vsc_pfn[VTNET_MAXQ];
146	struct	vring_hqueue vsc_hq[VTNET_MAXQ];
147};
148
149/*
150 * Return the number of available descriptors in the vring taking care
151 * of the 16-bit index wraparound.
152 */
153static int
154hq_num_avail(struct vring_hqueue *hq)
155{
156	int ndesc;
157
158	if (*hq->hq_avail_idx >= hq->hq_cur_aidx)
159		ndesc = *hq->hq_avail_idx - hq->hq_cur_aidx;
160	else
161		ndesc = UINT16_MAX - hq->hq_cur_aidx + *hq->hq_avail_idx + 1;
162
163	assert(ndesc >= 0 && ndesc <= hq->hq_size);
164
165	return (ndesc);
166}
167
168static uint16_t
169pci_vtnet_qsize(int qnum)
170{
171	/* XXX no ctl queue currently */
172	if (qnum == VTNET_CTLQ) {
173		return (0);
174	}
175
176	/* XXX fixed currently. Maybe different for tx/rx/ctl */
177	return (VTNET_RINGSZ);
178}
179
180static void
181pci_vtnet_ring_reset(struct pci_vtnet_softc *sc, int ring)
182{
183	struct vring_hqueue *hq;
184
185	assert(ring < VTNET_MAXQ);
186
187	hq = &sc->vsc_hq[ring];
188
189	/*
190	 * Reset all soft state
191	 */
192	hq->hq_cur_aidx = 0;
193}
194
195static void
196pci_vtnet_update_status(struct pci_vtnet_softc *sc, uint32_t value)
197{
198
199	if (value == 0) {
200		DPRINTF(("vtnet: device reset requested !\n"));
201		pci_vtnet_ring_reset(sc, VTNET_RXQ);
202		pci_vtnet_ring_reset(sc, VTNET_TXQ);
203		sc->vsc_rx_ready = 0;
204	}
205
206	sc->vsc_status = value;
207}
208
209/*
210 * Called to send a buffer chain out to the tap device
211 */
212static void
213pci_vtnet_tap_tx(struct pci_vtnet_softc *sc, struct iovec *iov, int iovcnt,
214		 int len)
215{
216	char pad[60];
217
218	if (sc->vsc_tapfd == -1)
219		return;
220
221	/*
222	 * If the length is < 60, pad out to that and add the
223	 * extra zero'd segment to the iov. It is guaranteed that
224	 * there is always an extra iov available by the caller.
225	 */
226	if (len < 60) {
227		memset(pad, 0, 60 - len);
228		iov[iovcnt].iov_base = pad;
229		iov[iovcnt].iov_len = 60 - len;
230		iovcnt++;
231	}
232	(void) writev(sc->vsc_tapfd, iov, iovcnt);
233}
234
235/*
236 *  Called when there is read activity on the tap file descriptor.
237 * Each buffer posted by the guest is assumed to be able to contain
238 * an entire ethernet frame + rx header.
239 *  MP note: the dummybuf is only used for discarding frames, so there
240 * is no need for it to be per-vtnet or locked.
241 */
242static uint8_t dummybuf[2048];
243
244static void
245pci_vtnet_tap_rx(struct pci_vtnet_softc *sc)
246{
247	struct virtio_desc *vd;
248	struct virtio_used *vu;
249	struct vring_hqueue *hq;
250	struct virtio_net_rxhdr *vrx;
251	uint8_t *buf;
252	int i;
253	int len;
254	int ndescs;
255	int didx, uidx, aidx;	/* descriptor, avail and used index */
256
257	/*
258	 * Should never be called without a valid tap fd
259	 */
260	assert(sc->vsc_tapfd != -1);
261
262	/*
263	 * But, will be called when the rx ring hasn't yet
264	 * been set up.
265	 */
266	if (sc->vsc_rx_ready == 0) {
267		/*
268		 * Drop the packet and try later.
269		 */
270		(void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf));
271		return;
272	}
273
274	/*
275	 * Calculate the number of available rx buffers
276	 */
277	hq = &sc->vsc_hq[VTNET_RXQ];
278
279	ndescs = hq_num_avail(hq);
280
281	if (ndescs == 0) {
282		/*
283		 * Need to wait for host notification to read
284		 */
285		if (sc->vsc_rxpend == 0) {
286			WPRINTF(("vtnet: no rx descriptors !\n"));
287			sc->vsc_rxpend = 1;
288		}
289
290		/*
291		 * Drop the packet and try later
292		 */
293		(void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf));
294		return;
295	}
296
297	aidx = hq->hq_cur_aidx;
298	uidx = *hq->hq_used_idx;
299	for (i = 0; i < ndescs; i++) {
300		/*
301		 * 'aidx' indexes into the an array of descriptor indexes
302		 */
303		didx = hq->hq_avail_ring[aidx % hq->hq_size];
304		assert(didx >= 0 && didx < hq->hq_size);
305
306		vd = &hq->hq_dtable[didx];
307
308		/*
309		 * Get a pointer to the rx header, and use the
310		 * data immediately following it for the packet buffer.
311		 */
312		vrx = (struct virtio_net_rxhdr *)paddr_guest2host(vd->vd_addr);
313		buf = (uint8_t *)(vrx + 1);
314
315		len = read(sc->vsc_tapfd, buf,
316			   vd->vd_len - sizeof(struct virtio_net_rxhdr));
317
318		if (len < 0 && errno == EWOULDBLOCK) {
319			break;
320		}
321
322		/*
323		 * The only valid field in the rx packet header is the
324		 * number of buffers, which is always 1 without TSO
325		 * support.
326		 */
327		memset(vrx, 0, sizeof(struct virtio_net_rxhdr));
328		vrx->vrh_bufs = 1;
329
330		/*
331		 * Write this descriptor into the used ring
332		 */
333		vu = &hq->hq_used_ring[uidx % hq->hq_size];
334		vu->vu_idx = didx;
335		vu->vu_tlen = len + sizeof(struct virtio_net_rxhdr);
336		uidx++;
337		aidx++;
338	}
339
340	/*
341	 * Update the used pointer, and signal an interrupt if allowed
342	 */
343	*hq->hq_used_idx = uidx;
344	hq->hq_cur_aidx = aidx;
345
346	if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) {
347		sc->vsc_isr |= 1;
348		pci_generate_msi(sc->vsc_pi, 0);
349	}
350}
351
352static void
353pci_vtnet_tap_callback(int fd, enum ev_type type, void *param)
354{
355	struct pci_vtnet_softc *sc = param;
356
357	pthread_mutex_lock(&sc->vsc_mtx);
358	pci_vtnet_tap_rx(sc);
359	pthread_mutex_unlock(&sc->vsc_mtx);
360
361}
362
363static void
364pci_vtnet_ping_rxq(struct pci_vtnet_softc *sc)
365{
366	/*
367	 * A qnotify means that the rx process can now begin
368	 */
369	if (sc->vsc_rx_ready == 0) {
370		sc->vsc_rx_ready = 1;
371	}
372
373	/*
374	 * If the rx queue was empty, attempt to receive a
375	 * packet that was previously blocked due to no rx bufs
376	 * available
377	 */
378	if (sc->vsc_rxpend) {
379		WPRINTF(("vtnet: rx resumed\n\r"));
380		sc->vsc_rxpend = 0;
381		pci_vtnet_tap_rx(sc);
382	}
383}
384
385static void
386pci_vtnet_proctx(struct pci_vtnet_softc *sc, struct vring_hqueue *hq)
387{
388	struct iovec iov[VTNET_MAXSEGS + 1];
389	struct virtio_desc *vd;
390	struct virtio_used *vu;
391	int i;
392	int plen;
393	int tlen;
394	int uidx, aidx, didx;
395
396	uidx = *hq->hq_used_idx;
397	aidx = hq->hq_cur_aidx;
398	didx = hq->hq_avail_ring[aidx % hq->hq_size];
399	assert(didx >= 0 && didx < hq->hq_size);
400
401	vd = &hq->hq_dtable[didx];
402
403	/*
404	 * Run through the chain of descriptors, ignoring the
405	 * first header descriptor. However, include the header
406	 * length in the total length that will be put into the
407	 * used queue.
408	 */
409	tlen = vd->vd_len;
410	vd = &hq->hq_dtable[vd->vd_next];
411
412	for (i = 0, plen = 0;
413	     i < VTNET_MAXSEGS;
414	     i++, vd = &hq->hq_dtable[vd->vd_next]) {
415		iov[i].iov_base = paddr_guest2host(vd->vd_addr);
416		iov[i].iov_len = vd->vd_len;
417		plen += vd->vd_len;
418		tlen += vd->vd_len;
419
420		if ((vd->vd_flags & VRING_DESC_F_NEXT) == 0)
421			break;
422	}
423	assert(i < VTNET_MAXSEGS);
424
425	DPRINTF(("virtio: packet send, %d bytes, %d segs\n\r", plen, i + 1));
426	pci_vtnet_tap_tx(sc, iov, i + 1, plen);
427
428	/*
429	 * Return this chain back to the host
430	 */
431	vu = &hq->hq_used_ring[uidx % hq->hq_size];
432	vu->vu_idx = didx;
433	vu->vu_tlen = tlen;
434	hq->hq_cur_aidx = aidx + 1;
435	*hq->hq_used_idx = uidx + 1;
436
437	/*
438	 * Generate an interrupt if able
439	 */
440	if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) {
441		sc->vsc_isr |= 1;
442		pci_generate_msi(sc->vsc_pi, 0);
443	}
444}
445
446static void
447pci_vtnet_ping_txq(struct pci_vtnet_softc *sc)
448{
449	struct vring_hqueue *hq = &sc->vsc_hq[VTNET_TXQ];
450	int i;
451	int ndescs;
452
453	/*
454	 * Calculate number of ring entries to process
455	 */
456	ndescs = hq_num_avail(hq);
457
458	if (ndescs == 0)
459		return;
460
461	/*
462	 * Run through all the entries, placing them into iovecs and
463	 * sending when an end-of-packet is found
464	 */
465	for (i = 0; i < ndescs; i++)
466		pci_vtnet_proctx(sc, hq);
467}
468
469static void
470pci_vtnet_ping_ctlq(struct pci_vtnet_softc *sc)
471{
472
473	DPRINTF(("vtnet: control qnotify!\n\r"));
474}
475
476static void
477pci_vtnet_ring_init(struct pci_vtnet_softc *sc, uint64_t pfn)
478{
479	struct vring_hqueue *hq;
480	int qnum = sc->vsc_curq;
481
482	assert(qnum < VTNET_MAXQ);
483
484	sc->vsc_pfn[qnum] = pfn << VRING_PFN;
485
486	/*
487	 * Set up host pointers to the various parts of the
488	 * queue
489	 */
490	hq = &sc->vsc_hq[qnum];
491	hq->hq_size = pci_vtnet_qsize(qnum);
492
493	hq->hq_dtable = paddr_guest2host(pfn << VRING_PFN);
494	hq->hq_avail_flags =  (uint16_t *)(hq->hq_dtable + hq->hq_size);
495	hq->hq_avail_idx = hq->hq_avail_flags + 1;
496	hq->hq_avail_ring = hq->hq_avail_flags + 2;
497	hq->hq_used_flags = (uint16_t *)roundup2((uintptr_t)hq->hq_avail_ring,
498						 VRING_ALIGN);
499	hq->hq_used_idx = hq->hq_used_flags + 1;
500	hq->hq_used_ring = (struct virtio_used *)(hq->hq_used_flags + 2);
501
502	/*
503	 * Initialize queue indexes
504	 */
505	hq->hq_cur_aidx = 0;
506}
507
508static int
509pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
510{
511	MD5_CTX mdctx;
512	unsigned char digest[16];
513	char nstr[80];
514	struct pci_vtnet_softc *sc;
515
516	/*
517	 * Access to guest memory is required. Fail if
518	 * memory not mapped
519	 */
520	if (paddr_guest2host(0) == NULL)
521		return (1);
522
523	sc = malloc(sizeof(struct pci_vtnet_softc));
524	memset(sc, 0, sizeof(struct pci_vtnet_softc));
525
526	pi->pi_arg = sc;
527	sc->vsc_pi = pi;
528
529	pthread_mutex_init(&sc->vsc_mtx, NULL);
530
531	/*
532	 * Attempt to open the tap device
533	 */
534	sc->vsc_tapfd = -1;
535	if (opts != NULL) {
536		char tbuf[80];
537
538		strcpy(tbuf, "/dev/");
539		strlcat(tbuf, opts, sizeof(tbuf));
540
541		sc->vsc_tapfd = open(tbuf, O_RDWR);
542		if (sc->vsc_tapfd == -1) {
543			WPRINTF(("open of tap device %s failed\n", tbuf));
544		} else {
545			/*
546			 * Set non-blocking and register for read
547			 * notifications with the event loop
548			 */
549			int opt = 1;
550			if (ioctl(sc->vsc_tapfd, FIONBIO, &opt) < 0) {
551				WPRINTF(("tap device O_NONBLOCK failed\n"));
552				close(sc->vsc_tapfd);
553				sc->vsc_tapfd = -1;
554			}
555
556			sc->vsc_mevp = mevent_add(sc->vsc_tapfd,
557						  EVF_READ,
558						  pci_vtnet_tap_callback,
559						  sc);
560			if (sc->vsc_mevp == NULL) {
561				WPRINTF(("Could not register event\n"));
562				close(sc->vsc_tapfd);
563				sc->vsc_tapfd = -1;
564			}
565		}
566	}
567
568	/*
569	 * The MAC address is the standard NetApp OUI of 00-a0-98,
570	 * followed by an MD5 of the vm name. The slot/func number is
571	 * prepended to this for slots other than 1:0, so that
572	 * a bootloader can netboot from the equivalent of slot 1.
573	 */
574	if (pi->pi_slot == 1 && pi->pi_func == 0) {
575		strncpy(nstr, vmname, sizeof(nstr));
576	} else {
577		snprintf(nstr, sizeof(nstr), "%d-%d-%s", pi->pi_slot,
578		    pi->pi_func, vmname);
579	}
580
581	MD5Init(&mdctx);
582	MD5Update(&mdctx, nstr, strlen(nstr));
583	MD5Final(digest, &mdctx);
584
585	sc->vsc_macaddr[0] = 0x00;
586	sc->vsc_macaddr[1] = 0xa0;
587	sc->vsc_macaddr[2] = 0x98;
588	sc->vsc_macaddr[3] = digest[0];
589	sc->vsc_macaddr[4] = digest[1];
590	sc->vsc_macaddr[5] = digest[2];
591
592	/* initialize config space */
593	pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET);
594	pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
595	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK);
596	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET);
597	pci_emul_add_msicap(pi, 1);
598	pci_emul_alloc_bar(pi, 0, PCIBAR_IO, VTNET_REGSZ);
599
600	return (0);
601}
602
603/*
604 * Function pointer array to handle queue notifications
605 */
606static void (*pci_vtnet_qnotify[VTNET_MAXQ])(struct pci_vtnet_softc *) = {
607	pci_vtnet_ping_rxq,
608	pci_vtnet_ping_txq,
609	pci_vtnet_ping_ctlq
610};
611
612static void
613pci_vtnet_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
614		int baridx, uint64_t offset, int size, uint64_t value)
615{
616	struct pci_vtnet_softc *sc = pi->pi_arg;
617	void *ptr;
618
619	assert(baridx == 0);
620
621	if (offset + size > VTNET_REGSZ) {
622		DPRINTF(("vtnet_write: 2big, offset %ld size %d\n",
623			 offset, size));
624		return;
625	}
626
627	pthread_mutex_lock(&sc->vsc_mtx);
628
629	switch (offset) {
630	case VTCFG_R_GUESTCAP:
631		assert(size == 4);
632		sc->vsc_features = value & VTNET_S_HOSTCAPS;
633		break;
634	case VTCFG_R_PFN:
635		assert(size == 4);
636		pci_vtnet_ring_init(sc, value);
637		break;
638	case VTCFG_R_QSEL:
639		assert(size == 2);
640		assert(value < VTNET_MAXQ);
641		sc->vsc_curq = value;
642		break;
643	case VTCFG_R_QNOTIFY:
644		assert(size == 2);
645		assert(value < VTNET_MAXQ);
646		(*pci_vtnet_qnotify[value])(sc);
647		break;
648	case VTCFG_R_STATUS:
649		assert(size == 1);
650		pci_vtnet_update_status(sc, value);
651		break;
652	case VTNET_R_CFG0:
653	case VTNET_R_CFG1:
654	case VTNET_R_CFG2:
655	case VTNET_R_CFG3:
656	case VTNET_R_CFG4:
657	case VTNET_R_CFG5:
658		assert((size + offset) <= (VTNET_R_CFG5 + 1));
659		ptr = &sc->vsc_macaddr[offset - VTNET_R_CFG0];
660		/*
661		 * The driver is allowed to change the MAC address
662		 */
663		sc->vsc_macaddr[offset - VTNET_R_CFG0] = value;
664		if (size == 1) {
665			*(uint8_t *) ptr = value;
666		} else if (size == 2) {
667			*(uint16_t *) ptr = value;
668		} else {
669			*(uint32_t *) ptr = value;
670		}
671		break;
672	case VTCFG_R_HOSTCAP:
673	case VTCFG_R_QNUM:
674	case VTCFG_R_ISR:
675	case VTNET_R_CFG6:
676	case VTNET_R_CFG7:
677		DPRINTF(("vtnet: write to readonly reg %ld\n\r", offset));
678		break;
679	default:
680		DPRINTF(("vtnet: unknown i/o write offset %ld\n\r", offset));
681		value = 0;
682		break;
683	}
684
685	pthread_mutex_unlock(&sc->vsc_mtx);
686}
687
688uint64_t
689pci_vtnet_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
690	       int baridx, uint64_t offset, int size)
691{
692	struct pci_vtnet_softc *sc = pi->pi_arg;
693	void *ptr;
694	uint64_t value;
695
696	assert(baridx == 0);
697
698	if (offset + size > VTNET_REGSZ) {
699		DPRINTF(("vtnet_read: 2big, offset %ld size %d\n",
700			 offset, size));
701		return (0);
702	}
703
704	pthread_mutex_lock(&sc->vsc_mtx);
705
706	switch (offset) {
707	case VTCFG_R_HOSTCAP:
708		assert(size == 4);
709		value = VTNET_S_HOSTCAPS;
710		break;
711	case VTCFG_R_GUESTCAP:
712		assert(size == 4);
713		value = sc->vsc_features; /* XXX never read ? */
714		break;
715	case VTCFG_R_PFN:
716		assert(size == 4);
717		value = sc->vsc_pfn[sc->vsc_curq] >> VRING_PFN;
718		break;
719	case VTCFG_R_QNUM:
720		assert(size == 2);
721		value = pci_vtnet_qsize(sc->vsc_curq);
722		break;
723	case VTCFG_R_QSEL:
724		assert(size == 2);
725		value = sc->vsc_curq;  /* XXX never read ? */
726		break;
727	case VTCFG_R_QNOTIFY:
728		assert(size == 2);
729		value = sc->vsc_curq;  /* XXX never read ? */
730		break;
731	case VTCFG_R_STATUS:
732		assert(size == 1);
733		value = sc->vsc_status;
734		break;
735	case VTCFG_R_ISR:
736		assert(size == 1);
737		value = sc->vsc_isr;
738		sc->vsc_isr = 0;     /* a read clears this flag */
739		break;
740	case VTNET_R_CFG0:
741	case VTNET_R_CFG1:
742	case VTNET_R_CFG2:
743	case VTNET_R_CFG3:
744	case VTNET_R_CFG4:
745	case VTNET_R_CFG5:
746                assert((size + offset) <= (VTNET_R_CFG5 + 1));
747                ptr = &sc->vsc_macaddr[offset - VTNET_R_CFG0];
748                if (size == 1) {
749                        value = *(uint8_t *) ptr;
750                } else if (size == 2) {
751                        value = *(uint16_t *) ptr;
752                } else {
753                        value = *(uint32_t *) ptr;
754                }
755		break;
756	case VTNET_R_CFG6:
757		assert(size != 4);
758		value = 0x01; /* XXX link always up */
759		break;
760	case VTNET_R_CFG7:
761		assert(size == 1);
762		value = 0; /* XXX link status in LSB */
763		break;
764	default:
765		DPRINTF(("vtnet: unknown i/o read offset %ld\n\r", offset));
766		value = 0;
767		break;
768	}
769
770	pthread_mutex_unlock(&sc->vsc_mtx);
771
772	return (value);
773}
774
775struct pci_devemu pci_de_vnet = {
776	.pe_emu = 	"virtio-net",
777	.pe_init =	pci_vtnet_init,
778	.pe_barwrite =	pci_vtnet_write,
779	.pe_barread =	pci_vtnet_read
780};
781PCI_EMUL_SET(pci_de_vnet);
782