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 /*
27  * This file and its contents are supplied under the terms of the
28  * Common Development and Distribution License ("CDDL"), version 1.0.
29  * You may only use this file in accordance with the terms of version
30  * 1.0 of the CDDL.
31  *
32  * A full copy of the text of the CDDL should have accompanied this
33  * source.  A copy of the CDDL is also available via the Internet at
34  * http://www.illumos.org/license/CDDL.
35  *
36  * Copyright 2015 Pluribus Networks Inc.
37  */
38 
39 #include <sys/cdefs.h>
40 
41 #include <sys/param.h>
42 #include <sys/linker_set.h>
43 #include <sys/ioctl.h>
44 #include <sys/viona_io.h>
45 
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <stdint.h>
51 #include <string.h>
52 #include <strings.h>
53 #include <unistd.h>
54 #include <assert.h>
55 #include <pthread.h>
56 #include <signal.h>
57 #include <poll.h>
58 #include <libdladm.h>
59 #include <libdllink.h>
60 #include <libdlvnic.h>
61 
62 #include <machine/vmm.h>
63 #include <vmmapi.h>
64 
65 #include "bhyverun.h"
66 #include "pci_emul.h"
67 #include "virtio.h"
68 
69 #define	VIONA_RINGSZ	1024
70 
71 /*
72  * PCI config-space register offsets
73  */
74 #define	VIONA_R_CFG0	24
75 #define	VIONA_R_CFG1	25
76 #define	VIONA_R_CFG2	26
77 #define	VIONA_R_CFG3	27
78 #define	VIONA_R_CFG4	28
79 #define	VIONA_R_CFG5	29
80 #define	VIONA_R_CFG6	30
81 #define	VIONA_R_CFG7	31
82 #define	VIONA_R_MAX	31
83 
84 #define	VIONA_REGSZ	VIONA_R_MAX+1
85 
86 /*
87  * Host capabilities
88  */
89 #define	VIRTIO_NET_F_MAC	(1 <<  5) /* host supplies MAC */
90 #define	VIRTIO_NET_F_MRG_RXBUF	(1 << 15) /* host can merge RX buffers */
91 #define	VIRTIO_NET_F_STATUS	(1 << 16) /* config status field available */
92 
93 #define	VIONA_S_HOSTCAPS		\
94 	(VIRTIO_NET_F_MAC |		\
95 	VIRTIO_NET_F_MRG_RXBUF |	\
96 	VIRTIO_NET_F_STATUS)
97 
98 /*
99  * Queue definitions.
100  */
101 #define	VIONA_RXQ	0
102 #define	VIONA_TXQ	1
103 #define	VIONA_CTLQ	2
104 
105 #define	VIONA_MAXQ	3
106 
107 /*
108  * Debug printf
109  */
110 static int pci_viona_debug;
111 #define	DPRINTF(params) if (pci_viona_debug) printf params
112 #define	WPRINTF(params) printf params
113 
114 /*
115  * Per-device softc
116  */
117 struct pci_viona_softc {
118 	struct pci_devinst *vsc_pi;
119 	pthread_mutex_t vsc_mtx;
120 
121 	int		vsc_curq;
122 	int		vsc_status;
123 	int		vsc_isr;
124 
125 	datalink_id_t	vsc_linkid;
126 	char		vsc_linkname[MAXLINKNAMELEN];
127 	int		vsc_vnafd;
128 
129 	uint32_t	vsc_features;
130 	uint8_t		vsc_macaddr[6];
131 
132 	uint64_t	vsc_pfn[VIONA_MAXQ];
133 	uint16_t	vsc_msix_table_idx[VIONA_MAXQ];
134 	/*
135 	 * Flag to see if host is already sending data out.
136 	 * If it is, no need to wait for lock and send interrupt to host
137 	 * for new data.
138 	 */
139 	boolean_t	vsc_tx_kick_lock_held;
140 
141 	pthread_t	tx_tid;
142 	pthread_mutex_t	tx_mtx;
143 	pthread_cond_t	tx_cond;
144 };
145 #define	viona_ctx(sc)	((sc)->vsc_pi->pi_vmctx)
146 
147 /*
148  * Return the size of IO BAR that maps virtio header and device specific
149  * region. The size would vary depending on whether MSI-X is enabled or
150  * not.
151  */
152 static uint64_t
153 pci_viona_iosize(struct pci_devinst *pi)
154 {
155 	if (pci_msix_enabled(pi))
156 		return (VIONA_REGSZ);
157 	else
158 		return (VIONA_REGSZ - (VTCFG_R_CFG1 - VTCFG_R_MSIX));
159 }
160 
161 static uint16_t
162 pci_viona_qsize(int qnum)
163 {
164 	/* XXX no ctl queue currently */
165 	if (qnum == VIONA_CTLQ) {
166 		return (0);
167 	}
168 
169 	/* XXX fixed currently. Maybe different for tx/rx/ctl */
170 	return (VIONA_RINGSZ);
171 }
172 
173 static void
174 pci_viona_ring_reset(struct pci_viona_softc *sc, int ring)
175 {
176 	int	error;
177 
178 	assert(ring < VIONA_MAXQ);
179 
180 	switch (ring) {
181 	case VIONA_RXQ:
182 		error = ioctl(sc->vsc_vnafd, VNA_IOC_RX_RING_RESET);
183 		if (error != 0) {
184 			WPRINTF(("ioctl viona rx ring reset failed %d\n",
185 			    error));
186 		} else {
187 			sc->vsc_pfn[VIONA_RXQ] = 0;
188 		}
189 		break;
190 	case VIONA_TXQ:
191 		error = ioctl(sc->vsc_vnafd, VNA_IOC_TX_RING_RESET);
192 		if (error != 0) {
193 			WPRINTF(("ioctl viona tx ring reset failed %d\n",
194 			    error));
195 		} else {
196 			sc->vsc_pfn[VIONA_TXQ] = 0;
197 		}
198 		break;
199 	case VIONA_CTLQ:
200 	default:
201 		break;
202 	}
203 }
204 
205 static void
206 pci_viona_update_status(struct pci_viona_softc *sc, uint32_t value)
207 {
208 
209 	if (value == 0) {
210 		DPRINTF(("viona: device reset requested !\n"));
211 		pci_viona_ring_reset(sc, VIONA_RXQ);
212 		pci_viona_ring_reset(sc, VIONA_TXQ);
213 	}
214 
215 	sc->vsc_status = value;
216 }
217 
218 static void *
219 pci_viona_poll_thread(void *param)
220 {
221 	struct pci_viona_softc *sc = param;
222 	pollfd_t	pollset;
223 	int			error;
224 
225 	pollset.fd = sc->vsc_vnafd;
226 	pollset.events = POLLIN | POLLOUT;
227 
228 	for (;;) {
229 		if (poll(&pollset, 1, -1) < 0) {
230 			if (errno == EINTR || errno == EAGAIN) {
231 				continue;
232 			} else {
233 				WPRINTF(("pci_viona_poll_thread poll()"
234 				    "error %d\n", errno));
235 				break;
236 			}
237 		}
238 		if (pollset.revents & POLLIN) {
239 			pci_generate_msix(sc->vsc_pi,
240 			    sc->vsc_msix_table_idx[VIONA_RXQ]);
241 			error = ioctl(sc->vsc_vnafd, VNA_IOC_RX_INTR_CLR);
242 			if (error != 0) {
243 				WPRINTF(("ioctl viona rx intr clear failed"
244 				    " %d\n", error));
245 			}
246 		}
247 
248 		if (pollset.revents & POLLOUT) {
249 			pci_generate_msix(sc->vsc_pi,
250 			    sc->vsc_msix_table_idx[VIONA_TXQ]);
251 			error = ioctl(sc->vsc_vnafd, VNA_IOC_TX_INTR_CLR);
252 			if (error != 0) {
253 				WPRINTF(("ioctl viona tx intr clear failed"
254 				    " %d\n", error));
255 			}
256 		}
257 	}
258 
259 	pthread_exit(NULL);
260 }
261 
262 static void
263 pci_viona_ping_rxq(struct pci_viona_softc *sc)
264 {
265 	int error;
266 
267 	error = ioctl(sc->vsc_vnafd, VNA_IOC_RX_RING_KICK);
268 	if (error != 0) {
269 		WPRINTF(("ioctl viona rx ring kick failed %d\n", error));
270 	}
271 }
272 
273 static void *
274 pci_viona_tx_thread(void *param)
275 {
276 	struct pci_viona_softc *sc = (struct pci_viona_softc *)param;
277 	int error;
278 
279 	pthread_mutex_lock(&sc->tx_mtx);
280 	for (;;) {
281 		error = pthread_cond_wait(&sc->tx_cond, &sc->tx_mtx);
282 		assert(error == 0);
283 		sc->vsc_tx_kick_lock_held = B_TRUE;
284 		error = ioctl(sc->vsc_vnafd, VNA_IOC_TX_RING_KICK);
285 		if (error != 0) {
286 			WPRINTF(("ioctl viona tx ring kick failed %d\n",
287 			    error));
288 		}
289 		sc->vsc_tx_kick_lock_held = B_FALSE;
290 	}
291 	pthread_mutex_unlock(&sc->tx_mtx);
292 }
293 
294 static void
295 pci_viona_ping_txq(struct pci_viona_softc *sc)
296 {
297 	/* Signal the tx thread for processing */
298 	if (sc->vsc_tx_kick_lock_held)
299 		return;
300 	pthread_mutex_lock(&sc->tx_mtx);
301 	pthread_cond_signal(&sc->tx_cond);
302 	pthread_mutex_unlock(&sc->tx_mtx);
303 }
304 
305 static void
306 pci_viona_ping_ctlq(struct pci_viona_softc *sc)
307 {
308 	DPRINTF(("viona: control qnotify!\n\r"));
309 }
310 
311 static void
312 pci_viona_ring_init(struct pci_viona_softc *sc, uint64_t pfn)
313 {
314 	int			qnum = sc->vsc_curq;
315 	vioc_ring_init_t	vna_ri;
316 	int			error;
317 
318 	assert(qnum < VIONA_MAXQ);
319 
320 	sc->vsc_pfn[qnum] = (pfn << VRING_PFN);
321 
322 	vna_ri.ri_qsize = pci_viona_qsize(qnum);
323 	vna_ri.ri_qaddr = (pfn << VRING_PFN);
324 
325 	switch (qnum) {
326 	case VIONA_RXQ:
327 		error = ioctl(sc->vsc_vnafd, VNA_IOC_RX_RING_INIT, &vna_ri);
328 		if (error != 0) {
329 			WPRINTF(("ioctl viona rx ring init failed %d\n",
330 			    error));
331 		}
332 		break;
333 	case VIONA_TXQ:
334 		error = ioctl(sc->vsc_vnafd, VNA_IOC_TX_RING_INIT, &vna_ri);
335 		if (error != 0) {
336 			WPRINTF(("ioctl viona tx ring init failed %d\n",
337 			    error));
338 		}
339 		break;
340 	case VIONA_CTLQ:
341 	default:
342 		break;
343 	}
344 }
345 
346 static int
347 pci_viona_viona_init(struct vmctx *ctx, struct pci_viona_softc *sc)
348 {
349 	vioc_create_t		vna_create;
350 	char			devname[MAXNAMELEN];
351 	int			ctlfd;
352 	int			error;
353 
354 	sc->vsc_vnafd = open("/devices/pseudo/viona@0:ctl", O_RDWR | O_EXCL);
355 	if (sc->vsc_vnafd == -1) {
356 		WPRINTF(("open viona ctl failed\n"));
357 		return (-1);
358 	}
359 
360 	vna_create.c_linkid = sc->vsc_linkid;
361 	strlcpy(vna_create.c_vmname, vmname,
362 	    sizeof (vna_create.c_vmname));
363 	vm_get_memory_seg(ctx, 1 * (1024 * 1024UL), &vna_create.c_lomem_size,
364 	    NULL);
365 	vm_get_memory_seg(ctx, 4 * (1024 * 1024 * 1024UL),
366 	    &vna_create.c_himem_size, NULL);
367 	error = ioctl(sc->vsc_vnafd, VNA_IOC_CREATE, &vna_create);
368 	if (error != 0) {
369 		WPRINTF(("ioctl viona create failed %d\n", error));
370 		return (-1);
371 	}
372 
373 	return (0);
374 }
375 
376 static int
377 pci_viona_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
378 {
379 	dladm_handle_t		handle;
380 	dladm_status_t		status;
381 	dladm_vnic_attr_t	attr;
382 	char			errmsg[DLADM_STRSIZE];
383 	int error;
384 	struct pci_viona_softc *sc;
385 	int i;
386 
387 	if (opts == NULL) {
388 		printf("virtio-viona: vnic required\n");
389 		return (1);
390 	}
391 
392 	sc = malloc(sizeof (struct pci_viona_softc));
393 	memset(sc, 0, sizeof (struct pci_viona_softc));
394 
395 	pi->pi_arg = sc;
396 	sc->vsc_pi = pi;
397 
398 	pthread_mutex_init(&sc->vsc_mtx, NULL);
399 
400 	strlcpy(sc->vsc_linkname, opts, MAXLINKNAMELEN);
401 
402 	if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) {
403 		WPRINTF(("could not open /dev/dld"));
404 		free(sc);
405 		return (1);
406 	}
407 
408 	if (dladm_name2info(handle, sc->vsc_linkname, &sc->vsc_linkid,
409 	    NULL, NULL, NULL) != DLADM_STATUS_OK) {
410 		WPRINTF(("dladm_name2info() for %s failed: %s\n", opts,
411 		    dladm_status2str(status, errmsg)));
412 		dladm_close(handle);
413 		free(sc);
414 		return (1);
415 	}
416 
417 	if (dladm_vnic_info(handle, sc->vsc_linkid, &attr,
418 	    DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) {
419 		WPRINTF(("dladm_vnic_info() for %s failed: %s\n", opts,
420 		    dladm_status2str(status, errmsg)));
421 		dladm_close(handle);
422 		free(sc);
423 		return (1);
424 	}
425 
426 	sc->vsc_tx_kick_lock_held = B_FALSE;
427 	memcpy(sc->vsc_macaddr, attr.va_mac_addr, ETHERADDRL);
428 
429 	dladm_close(handle);
430 
431 	error = pci_viona_viona_init(ctx, sc);
432 	if (error != 0) {
433 		free(sc);
434 		return (1);
435 	}
436 
437 	error = pthread_create(NULL, NULL, pci_viona_poll_thread, sc);
438 	assert(error == 0);
439 
440 	/* initialize config space */
441 	pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET);
442 	pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
443 	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK);
444 	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET);
445 
446 	/* MSI-X support */
447 	for (i = 0; i < VIONA_MAXQ; i++)
448 		sc->vsc_msix_table_idx[i] = VIRTIO_MSI_NO_VECTOR;
449 
450 	/*
451 	 * BAR 1 used to map MSI-X table and PBA
452 	 */
453 	if (pci_emul_add_msixcap(pi, VIONA_MAXQ, 1)) {
454 		free(sc);
455 		return (1);
456 	}
457 
458 	pci_emul_alloc_bar(pi, 0, PCIBAR_IO, VIONA_REGSZ);
459 
460 	/*
461 	 * Initialize tx semaphore & spawn TX processing thread
462 	 * As of now, only one thread for TX desc processing is
463 	 * spawned.
464 	 */
465 	pthread_mutex_init(&sc->tx_mtx, NULL);
466 	pthread_cond_init(&sc->tx_cond, NULL);
467 	pthread_create(&sc->tx_tid, NULL, pci_viona_tx_thread, (void *)sc);
468 
469 	return (0);
470 }
471 
472 /*
473  * Function pointer array to handle queue notifications
474  */
475 static void (*pci_viona_qnotify[VIONA_MAXQ])(struct pci_viona_softc *) = {
476 	pci_viona_ping_rxq,
477 	pci_viona_ping_txq,
478 	pci_viona_ping_ctlq
479 };
480 
481 static uint64_t
482 viona_adjust_offset(struct pci_devinst *pi, uint64_t offset)
483 {
484 	/*
485 	 * Device specific offsets used by guest would change based on
486 	 * whether MSI-X capability is enabled or not
487 	 */
488 	if (!pci_msix_enabled(pi)) {
489 		if (offset >= VTCFG_R_MSIX)
490 			return (offset + (VTCFG_R_CFG1 - VTCFG_R_MSIX));
491 	}
492 
493 	return (offset);
494 }
495 
496 static void
497 pci_viona_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
498 		int baridx, uint64_t offset, int size, uint64_t value)
499 {
500 	struct pci_viona_softc *sc = pi->pi_arg;
501 	void *ptr;
502 	int err = 0;
503 
504 	if (baridx == pci_msix_table_bar(pi) ||
505 	    baridx == pci_msix_pba_bar(pi)) {
506 		pci_emul_msix_twrite(pi, offset, size, value);
507 		return;
508 	}
509 
510 	assert(baridx == 0);
511 
512 	if (offset + size > pci_viona_iosize(pi)) {
513 		DPRINTF(("viona_write: 2big, offset %ld size %d\n",
514 		    offset, size));
515 		return;
516 	}
517 
518 	pthread_mutex_lock(&sc->vsc_mtx);
519 
520 	offset = viona_adjust_offset(pi, offset);
521 
522 	switch (offset) {
523 	case VTCFG_R_GUESTCAP:
524 		assert(size == 4);
525 		err = ioctl(sc->vsc_vnafd, VNA_IOC_SET_FEATURES, &value);
526 		if (err != 0)
527 			WPRINTF(("ioctl feature negotiation returned"
528 			    " err = %d\n", err));
529 		break;
530 	case VTCFG_R_PFN:
531 		assert(size == 4);
532 		pci_viona_ring_init(sc, value);
533 		break;
534 	case VTCFG_R_QSEL:
535 		assert(size == 2);
536 		assert(value < VIONA_MAXQ);
537 		sc->vsc_curq = value;
538 		break;
539 	case VTCFG_R_QNOTIFY:
540 		assert(size == 2);
541 		assert(value < VIONA_MAXQ);
542 		(*pci_viona_qnotify[value])(sc);
543 		break;
544 	case VTCFG_R_STATUS:
545 		assert(size == 1);
546 		pci_viona_update_status(sc, value);
547 		break;
548 	case VTCFG_R_CFGVEC:
549 		assert(size == 2);
550 		sc->vsc_msix_table_idx[VIONA_CTLQ] = value;
551 		break;
552 	case VTCFG_R_QVEC:
553 		assert(size == 2);
554 		assert(sc->vsc_curq != VIONA_CTLQ);
555 		sc->vsc_msix_table_idx[sc->vsc_curq] = value;
556 		break;
557 	case VIONA_R_CFG0:
558 	case VIONA_R_CFG1:
559 	case VIONA_R_CFG2:
560 	case VIONA_R_CFG3:
561 	case VIONA_R_CFG4:
562 	case VIONA_R_CFG5:
563 		assert((size + offset) <= (VIONA_R_CFG5 + 1));
564 		ptr = &sc->vsc_macaddr[offset - VIONA_R_CFG0];
565 		/*
566 		 * The driver is allowed to change the MAC address
567 		 */
568 		sc->vsc_macaddr[offset - VIONA_R_CFG0] = value;
569 		if (size == 1) {
570 			*(uint8_t *)ptr = value;
571 		} else if (size == 2) {
572 			*(uint16_t *)ptr = value;
573 		} else {
574 			*(uint32_t *)ptr = value;
575 		}
576 		break;
577 	case VTCFG_R_HOSTCAP:
578 	case VTCFG_R_QNUM:
579 	case VTCFG_R_ISR:
580 	case VIONA_R_CFG6:
581 	case VIONA_R_CFG7:
582 		DPRINTF(("viona: write to readonly reg %ld\n\r", offset));
583 		break;
584 	default:
585 		DPRINTF(("viona: unknown i/o write offset %ld\n\r", offset));
586 		value = 0;
587 		break;
588 	}
589 
590 	pthread_mutex_unlock(&sc->vsc_mtx);
591 }
592 
593 uint64_t
594 pci_viona_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
595     int baridx, uint64_t offset, int size)
596 {
597 	struct pci_viona_softc *sc = pi->pi_arg;
598 	void *ptr;
599 	uint64_t value;
600 	int err = 0;
601 
602 	if (baridx == pci_msix_table_bar(pi) ||
603 	    baridx == pci_msix_pba_bar(pi)) {
604 		return (pci_emul_msix_tread(pi, offset, size));
605 	}
606 
607 	assert(baridx == 0);
608 
609 	if (offset + size > pci_viona_iosize(pi)) {
610 		DPRINTF(("viona_read: 2big, offset %ld size %d\n",
611 		    offset, size));
612 		return (0);
613 	}
614 
615 	pthread_mutex_lock(&sc->vsc_mtx);
616 
617 	offset = viona_adjust_offset(pi, offset);
618 
619 	switch (offset) {
620 	case VTCFG_R_HOSTCAP:
621 		assert(size == 4);
622 		err = ioctl(sc->vsc_vnafd, VNA_IOC_GET_FEATURES, &value);
623 		if (err != 0)
624 			WPRINTF(("ioctl get host features returned"
625 			    " err = %d\n", err));
626 		break;
627 	case VTCFG_R_GUESTCAP:
628 		assert(size == 4);
629 		value = sc->vsc_features; /* XXX never read ? */
630 		break;
631 	case VTCFG_R_PFN:
632 		assert(size == 4);
633 		value = sc->vsc_pfn[sc->vsc_curq] >> VRING_PFN;
634 		break;
635 	case VTCFG_R_QNUM:
636 		assert(size == 2);
637 		value = pci_viona_qsize(sc->vsc_curq);
638 		break;
639 	case VTCFG_R_QSEL:
640 		assert(size == 2);
641 		value = sc->vsc_curq;  /* XXX never read ? */
642 		break;
643 	case VTCFG_R_QNOTIFY:
644 		assert(size == 2);
645 		value = sc->vsc_curq;  /* XXX never read ? */
646 		break;
647 	case VTCFG_R_STATUS:
648 		assert(size == 1);
649 		value = sc->vsc_status;
650 		break;
651 	case VTCFG_R_ISR:
652 		assert(size == 1);
653 		value = sc->vsc_isr;
654 		sc->vsc_isr = 0;	/* a read clears this flag */
655 		break;
656 	case VTCFG_R_CFGVEC:
657 		assert(size == 2);
658 		value = sc->vsc_msix_table_idx[VIONA_CTLQ];
659 		break;
660 	case VTCFG_R_QVEC:
661 		assert(size == 2);
662 		assert(sc->vsc_curq != VIONA_CTLQ);
663 		value = sc->vsc_msix_table_idx[sc->vsc_curq];
664 		break;
665 	case VIONA_R_CFG0:
666 	case VIONA_R_CFG1:
667 	case VIONA_R_CFG2:
668 	case VIONA_R_CFG3:
669 	case VIONA_R_CFG4:
670 	case VIONA_R_CFG5:
671 		assert((size + offset) <= (VIONA_R_CFG5 + 1));
672 		ptr = &sc->vsc_macaddr[offset - VIONA_R_CFG0];
673 		if (size == 1) {
674 			value = *(uint8_t *)ptr;
675 		} else if (size == 2) {
676 			value = *(uint16_t *)ptr;
677 		} else {
678 			value = *(uint32_t *)ptr;
679 		}
680 		break;
681 	case VIONA_R_CFG6:
682 		assert(size != 4);
683 		value = 0x01;	/* XXX link always up */
684 		break;
685 	case VIONA_R_CFG7:
686 		assert(size == 1);
687 		value = 0;	/* XXX link status in LSB */
688 		break;
689 	default:
690 		DPRINTF(("viona: unknown i/o read offset %ld\n\r", offset));
691 		value = 0;
692 		break;
693 	}
694 
695 	pthread_mutex_unlock(&sc->vsc_mtx);
696 
697 	return (value);
698 }
699 
700 struct pci_devemu pci_de_viona = {
701 	.pe_emu = 	"virtio-net-viona",
702 	.pe_init =	pci_viona_init,
703 	.pe_barwrite =	pci_viona_write,
704 	.pe_barread =	pci_viona_read
705 };
706 PCI_EMUL_SET(pci_de_viona);
707