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