1bf21cd93STycho Nightingale /*
2bf21cd93STycho Nightingale  * Copyright (c) 2011 NetApp, Inc.
3bf21cd93STycho Nightingale  * All rights reserved.
4bf21cd93STycho Nightingale  *
5bf21cd93STycho Nightingale  * Redistribution and use in source and binary forms, with or without
6bf21cd93STycho Nightingale  * modification, are permitted provided that the following conditions
7bf21cd93STycho Nightingale  * are met:
8bf21cd93STycho Nightingale  * 1. Redistributions of source code must retain the above copyright
9bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer.
10bf21cd93STycho Nightingale  * 2. Redistributions in binary form must reproduce the above copyright
11bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer in the
12bf21cd93STycho Nightingale  *    documentation and/or other materials provided with the distribution.
13bf21cd93STycho Nightingale  *
14bf21cd93STycho Nightingale  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15bf21cd93STycho Nightingale  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16bf21cd93STycho Nightingale  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17bf21cd93STycho Nightingale  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18bf21cd93STycho Nightingale  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19bf21cd93STycho Nightingale  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20bf21cd93STycho Nightingale  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21bf21cd93STycho Nightingale  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22bf21cd93STycho Nightingale  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23bf21cd93STycho Nightingale  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24bf21cd93STycho Nightingale  * SUCH DAMAGE.
25bf21cd93STycho Nightingale  */
26bf21cd93STycho Nightingale /*
27bf21cd93STycho Nightingale  * This file and its contents are supplied under the terms of the
28bf21cd93STycho Nightingale  * Common Development and Distribution License ("CDDL"), version 1.0.
29bf21cd93STycho Nightingale  * You may only use this file in accordance with the terms of version
30bf21cd93STycho Nightingale  * 1.0 of the CDDL.
31bf21cd93STycho Nightingale  *
32bf21cd93STycho Nightingale  * A full copy of the text of the CDDL should have accompanied this
33bf21cd93STycho Nightingale  * source.  A copy of the CDDL is also available via the Internet at
34bf21cd93STycho Nightingale  * http://www.illumos.org/license/CDDL.
35bf21cd93STycho Nightingale  *
36bf21cd93STycho Nightingale  * Copyright 2015 Pluribus Networks Inc.
37b22a70abSPatrick Mooney  * Copyright 2019 Joyent, Inc.
38*f24fee03SAndy Fiddaman  * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
39bf21cd93STycho Nightingale  */
40bf21cd93STycho Nightingale 
41bf21cd93STycho Nightingale #include <sys/cdefs.h>
42bf21cd93STycho Nightingale 
43bf21cd93STycho Nightingale #include <sys/param.h>
44bf21cd93STycho Nightingale #include <sys/linker_set.h>
45bf21cd93STycho Nightingale #include <sys/ioctl.h>
46bf21cd93STycho Nightingale #include <sys/viona_io.h>
47bf21cd93STycho Nightingale 
48bf21cd93STycho Nightingale #include <errno.h>
49bf21cd93STycho Nightingale #include <fcntl.h>
50bf21cd93STycho Nightingale #include <stdio.h>
51bf21cd93STycho Nightingale #include <stdlib.h>
52bf21cd93STycho Nightingale #include <stdint.h>
53bf21cd93STycho Nightingale #include <string.h>
54bf21cd93STycho Nightingale #include <strings.h>
55bf21cd93STycho Nightingale #include <unistd.h>
56bf21cd93STycho Nightingale #include <assert.h>
57bf21cd93STycho Nightingale #include <pthread.h>
58bf21cd93STycho Nightingale #include <signal.h>
59bf21cd93STycho Nightingale #include <poll.h>
60bf21cd93STycho Nightingale #include <libdladm.h>
61bf21cd93STycho Nightingale #include <libdllink.h>
62bf21cd93STycho Nightingale #include <libdlvnic.h>
63bf21cd93STycho Nightingale 
64bf21cd93STycho Nightingale #include <machine/vmm.h>
65bf21cd93STycho Nightingale #include <vmmapi.h>
66bf21cd93STycho Nightingale 
67bf21cd93STycho Nightingale #include "bhyverun.h"
682b948146SAndy Fiddaman #include "config.h"
69bf21cd93STycho Nightingale #include "pci_emul.h"
70bf21cd93STycho Nightingale #include "virtio.h"
71bf21cd93STycho Nightingale 
72bf21cd93STycho Nightingale #define	VIONA_RINGSZ	1024
73bf21cd93STycho Nightingale 
74bf21cd93STycho Nightingale /*
75bf21cd93STycho Nightingale  * PCI config-space register offsets
76bf21cd93STycho Nightingale  */
77bf21cd93STycho Nightingale #define	VIONA_R_CFG0	24
78bf21cd93STycho Nightingale #define	VIONA_R_CFG1	25
79bf21cd93STycho Nightingale #define	VIONA_R_CFG2	26
80bf21cd93STycho Nightingale #define	VIONA_R_CFG3	27
81bf21cd93STycho Nightingale #define	VIONA_R_CFG4	28
82bf21cd93STycho Nightingale #define	VIONA_R_CFG5	29
83bf21cd93STycho Nightingale #define	VIONA_R_CFG6	30
84bf21cd93STycho Nightingale #define	VIONA_R_CFG7	31
85bf21cd93STycho Nightingale #define	VIONA_R_MAX	31
86bf21cd93STycho Nightingale 
87bf21cd93STycho Nightingale #define	VIONA_REGSZ	VIONA_R_MAX+1
88bf21cd93STycho Nightingale 
89bf21cd93STycho Nightingale /*
90bf21cd93STycho Nightingale  * Queue definitions.
91bf21cd93STycho Nightingale  */
92bf21cd93STycho Nightingale #define	VIONA_RXQ	0
93bf21cd93STycho Nightingale #define	VIONA_TXQ	1
94bf21cd93STycho Nightingale #define	VIONA_CTLQ	2
95bf21cd93STycho Nightingale 
96bf21cd93STycho Nightingale #define	VIONA_MAXQ	3
97bf21cd93STycho Nightingale 
98bf21cd93STycho Nightingale /*
99bf21cd93STycho Nightingale  * Debug printf
100bf21cd93STycho Nightingale  */
101b22a70abSPatrick Mooney static volatile int pci_viona_debug;
102bf21cd93STycho Nightingale #define	DPRINTF(params) if (pci_viona_debug) printf params
103bf21cd93STycho Nightingale #define	WPRINTF(params) printf params
104bf21cd93STycho Nightingale 
105bf21cd93STycho Nightingale /*
106bf21cd93STycho Nightingale  * Per-device softc
107bf21cd93STycho Nightingale  */
108bf21cd93STycho Nightingale struct pci_viona_softc {
109bf21cd93STycho Nightingale 	struct pci_devinst *vsc_pi;
110bf21cd93STycho Nightingale 	pthread_mutex_t vsc_mtx;
111bf21cd93STycho Nightingale 
112bf21cd93STycho Nightingale 	int		vsc_curq;
113bf21cd93STycho Nightingale 	int		vsc_status;
114bf21cd93STycho Nightingale 	int		vsc_isr;
115bf21cd93STycho Nightingale 
116bf21cd93STycho Nightingale 	datalink_id_t	vsc_linkid;
117bf21cd93STycho Nightingale 	int		vsc_vnafd;
118bf21cd93STycho Nightingale 
119b22a70abSPatrick Mooney 	/* Configurable parameters */
120b22a70abSPatrick Mooney 	char		vsc_linkname[MAXLINKNAMELEN];
121b22a70abSPatrick Mooney 	uint32_t	vsc_feature_mask;
122b22a70abSPatrick Mooney 	uint16_t	vsc_vq_size;
123b22a70abSPatrick Mooney 
124bf21cd93STycho Nightingale 	uint32_t	vsc_features;
125bf21cd93STycho Nightingale 	uint8_t		vsc_macaddr[6];
126bf21cd93STycho Nightingale 
127bf21cd93STycho Nightingale 	uint64_t	vsc_pfn[VIONA_MAXQ];
128bf21cd93STycho Nightingale 	uint16_t	vsc_msix_table_idx[VIONA_MAXQ];
129b22a70abSPatrick Mooney 	boolean_t	vsc_msix_active;
130bf21cd93STycho Nightingale };
131bf21cd93STycho Nightingale 
132bf21cd93STycho Nightingale /*
133bf21cd93STycho Nightingale  * Return the size of IO BAR that maps virtio header and device specific
134bf21cd93STycho Nightingale  * region. The size would vary depending on whether MSI-X is enabled or
135bf21cd93STycho Nightingale  * not.
136bf21cd93STycho Nightingale  */
137bf21cd93STycho Nightingale static uint64_t
138bf21cd93STycho Nightingale pci_viona_iosize(struct pci_devinst *pi)
139bf21cd93STycho Nightingale {
1402b948146SAndy Fiddaman 	if (pci_msix_enabled(pi)) {
141bf21cd93STycho Nightingale 		return (VIONA_REGSZ);
1422b948146SAndy Fiddaman 	} else {
1432b948146SAndy Fiddaman 		return (VIONA_REGSZ -
1442b948146SAndy Fiddaman 		    (VIRTIO_PCI_CONFIG_OFF(1) - VIRTIO_PCI_CONFIG_OFF(0)));
1452b948146SAndy Fiddaman 	}
146bf21cd93STycho Nightingale }
147bf21cd93STycho Nightingale 
148bf21cd93STycho Nightingale static uint16_t
149b22a70abSPatrick Mooney pci_viona_qsize(struct pci_viona_softc *sc, int qnum)
150bf21cd93STycho Nightingale {
151bf21cd93STycho Nightingale 	/* XXX no ctl queue currently */
152bf21cd93STycho Nightingale 	if (qnum == VIONA_CTLQ) {
153bf21cd93STycho Nightingale 		return (0);
154bf21cd93STycho Nightingale 	}
155bf21cd93STycho Nightingale 
156b22a70abSPatrick Mooney 	return (sc->vsc_vq_size);
157bf21cd93STycho Nightingale }
158bf21cd93STycho Nightingale 
159bf21cd93STycho Nightingale static void
160bf21cd93STycho Nightingale pci_viona_ring_reset(struct pci_viona_softc *sc, int ring)
161bf21cd93STycho Nightingale {
162bf21cd93STycho Nightingale 	assert(ring < VIONA_MAXQ);
163bf21cd93STycho Nightingale 
164bf21cd93STycho Nightingale 	switch (ring) {
165bf21cd93STycho Nightingale 	case VIONA_RXQ:
166bf21cd93STycho Nightingale 	case VIONA_TXQ:
167bf21cd93STycho Nightingale 		break;
168bf21cd93STycho Nightingale 	case VIONA_CTLQ:
169bf21cd93STycho Nightingale 	default:
170b22a70abSPatrick Mooney 		return;
171bf21cd93STycho Nightingale 	}
172b22a70abSPatrick Mooney 
173b22a70abSPatrick Mooney 	for (;;) {
174b22a70abSPatrick Mooney 		int res;
175b22a70abSPatrick Mooney 
176b22a70abSPatrick Mooney 		res = ioctl(sc->vsc_vnafd, VNA_IOC_RING_RESET, ring);
177b22a70abSPatrick Mooney 		if (res == 0) {
178b22a70abSPatrick Mooney 			break;
179b22a70abSPatrick Mooney 		} else if (errno != EINTR) {
180b22a70abSPatrick Mooney 			WPRINTF(("ioctl viona ring %d reset failed %d\n",
181b22a70abSPatrick Mooney 			    ring, errno));
182b22a70abSPatrick Mooney 			return;
183b22a70abSPatrick Mooney 		}
184b22a70abSPatrick Mooney 	}
185b22a70abSPatrick Mooney 
186b22a70abSPatrick Mooney 	sc->vsc_pfn[ring] = 0;
187bf21cd93STycho Nightingale }
188bf21cd93STycho Nightingale 
189bf21cd93STycho Nightingale static void
190bf21cd93STycho Nightingale pci_viona_update_status(struct pci_viona_softc *sc, uint32_t value)
191bf21cd93STycho Nightingale {
192bf21cd93STycho Nightingale 
193bf21cd93STycho Nightingale 	if (value == 0) {
194bf21cd93STycho Nightingale 		DPRINTF(("viona: device reset requested !\n"));
195bf21cd93STycho Nightingale 		pci_viona_ring_reset(sc, VIONA_RXQ);
196bf21cd93STycho Nightingale 		pci_viona_ring_reset(sc, VIONA_TXQ);
197bf21cd93STycho Nightingale 	}
198bf21cd93STycho Nightingale 
199bf21cd93STycho Nightingale 	sc->vsc_status = value;
200bf21cd93STycho Nightingale }
201bf21cd93STycho Nightingale 
202bf21cd93STycho Nightingale static void *
203bf21cd93STycho Nightingale pci_viona_poll_thread(void *param)
204bf21cd93STycho Nightingale {
205bf21cd93STycho Nightingale 	struct pci_viona_softc *sc = param;
206bf21cd93STycho Nightingale 	pollfd_t pollset;
207b22a70abSPatrick Mooney 	const int fd = sc->vsc_vnafd;
208bf21cd93STycho Nightingale 
209b22a70abSPatrick Mooney 	pollset.fd = fd;
210b22a70abSPatrick Mooney 	pollset.events = POLLRDBAND;
211bf21cd93STycho Nightingale 
212bf21cd93STycho Nightingale 	for (;;) {
213bf21cd93STycho Nightingale 		if (poll(&pollset, 1, -1) < 0) {
214bf21cd93STycho Nightingale 			if (errno == EINTR || errno == EAGAIN) {
215bf21cd93STycho Nightingale 				continue;
216bf21cd93STycho Nightingale 			} else {
217bf21cd93STycho Nightingale 				WPRINTF(("pci_viona_poll_thread poll()"
218bf21cd93STycho Nightingale 				    "error %d\n", errno));
219bf21cd93STycho Nightingale 				break;
220bf21cd93STycho Nightingale 			}
221bf21cd93STycho Nightingale 		}
222b22a70abSPatrick Mooney 		if (pollset.revents & POLLRDBAND) {
223b22a70abSPatrick Mooney 			vioc_intr_poll_t vip;
224b22a70abSPatrick Mooney 			uint_t i;
225b22a70abSPatrick Mooney 			int res;
226b22a70abSPatrick Mooney 			boolean_t assert_lintr = B_FALSE;
227b22a70abSPatrick Mooney 			const boolean_t do_msix = pci_msix_enabled(sc->vsc_pi);
228bf21cd93STycho Nightingale 
229b22a70abSPatrick Mooney 			res = ioctl(fd, VNA_IOC_INTR_POLL, &vip);
230b22a70abSPatrick Mooney 			for (i = 0; res > 0 && i < VIONA_VQ_MAX; i++) {
231b22a70abSPatrick Mooney 				if (vip.vip_status[i] == 0) {
232b22a70abSPatrick Mooney 					continue;
233b22a70abSPatrick Mooney 				}
234b22a70abSPatrick Mooney 				if (do_msix) {
235bf21cd93STycho Nightingale 					pci_generate_msix(sc->vsc_pi,
236b22a70abSPatrick Mooney 					    sc->vsc_msix_table_idx[i]);
237b22a70abSPatrick Mooney 				} else {
238b22a70abSPatrick Mooney 					assert_lintr = B_TRUE;
239b22a70abSPatrick Mooney 				}
240b22a70abSPatrick Mooney 				res = ioctl(fd, VNA_IOC_RING_INTR_CLR, i);
241b22a70abSPatrick Mooney 				if (res != 0) {
242b22a70abSPatrick Mooney 					WPRINTF(("ioctl viona vq %d intr "
243b22a70abSPatrick Mooney 					    "clear failed %d\n", i, errno));
244b22a70abSPatrick Mooney 				}
245b22a70abSPatrick Mooney 			}
246b22a70abSPatrick Mooney 			if (assert_lintr) {
247b22a70abSPatrick Mooney 				pthread_mutex_lock(&sc->vsc_mtx);
248b0de25cbSAndy Fiddaman 				sc->vsc_isr |= VIRTIO_PCI_ISR_INTR;
249b22a70abSPatrick Mooney 				pci_lintr_assert(sc->vsc_pi);
250b22a70abSPatrick Mooney 				pthread_mutex_unlock(&sc->vsc_mtx);
251bf21cd93STycho Nightingale 			}
252bf21cd93STycho Nightingale 		}
253bf21cd93STycho Nightingale 	}
254bf21cd93STycho Nightingale 
255bf21cd93STycho Nightingale 	pthread_exit(NULL);
256bf21cd93STycho Nightingale }
257bf21cd93STycho Nightingale 
258bf21cd93STycho Nightingale static void
259bf21cd93STycho Nightingale pci_viona_ring_init(struct pci_viona_softc *sc, uint64_t pfn)
260bf21cd93STycho Nightingale {
261bf21cd93STycho Nightingale 	int			qnum = sc->vsc_curq;
262bf21cd93STycho Nightingale 	vioc_ring_init_t	vna_ri;
263bf21cd93STycho Nightingale 	int			error;
264bf21cd93STycho Nightingale 
265bf21cd93STycho Nightingale 	assert(qnum < VIONA_MAXQ);
266bf21cd93STycho Nightingale 
267b22a70abSPatrick Mooney 	if (qnum == VIONA_CTLQ) {
268b22a70abSPatrick Mooney 		return;
269b22a70abSPatrick Mooney 	}
270b22a70abSPatrick Mooney 
271bf21cd93STycho Nightingale 	sc->vsc_pfn[qnum] = (pfn << VRING_PFN);
272bf21cd93STycho Nightingale 
273b22a70abSPatrick Mooney 	vna_ri.ri_index = qnum;
274b22a70abSPatrick Mooney 	vna_ri.ri_qsize = pci_viona_qsize(sc, qnum);
275bf21cd93STycho Nightingale 	vna_ri.ri_qaddr = (pfn << VRING_PFN);
276b22a70abSPatrick Mooney 	error = ioctl(sc->vsc_vnafd, VNA_IOC_RING_INIT, &vna_ri);
277bf21cd93STycho Nightingale 
278bf21cd93STycho Nightingale 	if (error != 0) {
279b22a70abSPatrick Mooney 		WPRINTF(("ioctl viona ring %u init failed %d\n", qnum, errno));
280bf21cd93STycho Nightingale 	}
281bf21cd93STycho Nightingale }
282bf21cd93STycho Nightingale 
283bf21cd93STycho Nightingale static int
284bf21cd93STycho Nightingale pci_viona_viona_init(struct vmctx *ctx, struct pci_viona_softc *sc)
285bf21cd93STycho Nightingale {
286bf21cd93STycho Nightingale 	vioc_create_t		vna_create;
287bf21cd93STycho Nightingale 	int			error;
288bf21cd93STycho Nightingale 
289b22a70abSPatrick Mooney 	sc->vsc_vnafd = open("/dev/viona", O_RDWR | O_EXCL);
290bf21cd93STycho Nightingale 	if (sc->vsc_vnafd == -1) {
291b22a70abSPatrick Mooney 		WPRINTF(("open viona ctl failed: %d\n", errno));
292bf21cd93STycho Nightingale 		return (-1);
293bf21cd93STycho Nightingale 	}
294bf21cd93STycho Nightingale 
295bf21cd93STycho Nightingale 	vna_create.c_linkid = sc->vsc_linkid;
296b22a70abSPatrick Mooney 	vna_create.c_vmfd = vm_get_device_fd(ctx);
297bf21cd93STycho Nightingale 	error = ioctl(sc->vsc_vnafd, VNA_IOC_CREATE, &vna_create);
298bf21cd93STycho Nightingale 	if (error != 0) {
299b22a70abSPatrick Mooney 		(void) close(sc->vsc_vnafd);
300b22a70abSPatrick Mooney 		WPRINTF(("ioctl viona create failed %d\n", errno));
301bf21cd93STycho Nightingale 		return (-1);
302bf21cd93STycho Nightingale 	}
303bf21cd93STycho Nightingale 
304bf21cd93STycho Nightingale 	return (0);
305bf21cd93STycho Nightingale }
306bf21cd93STycho Nightingale 
307bf21cd93STycho Nightingale static int
3082b948146SAndy Fiddaman pci_viona_legacy_config(nvlist_t *nvl, const char *opt)
309b22a70abSPatrick Mooney {
3102b948146SAndy Fiddaman 	char *config, *name, *tofree, *value;
3112b948146SAndy Fiddaman 
3122b948146SAndy Fiddaman 	if (opt == NULL)
3132b948146SAndy Fiddaman 		return (0);
3142b948146SAndy Fiddaman 
3152b948146SAndy Fiddaman 	config = tofree = strdup(opt);
3162b948146SAndy Fiddaman 	while ((name = strsep(&config, ",")) != NULL) {
3172b948146SAndy Fiddaman 		value = strchr(name, '=');
3182b948146SAndy Fiddaman 		if (value != NULL) {
3192b948146SAndy Fiddaman 			*value++ = '\0';
3202b948146SAndy Fiddaman 			set_config_value_node(nvl, name, value);
3212b948146SAndy Fiddaman 		} else {
3222b948146SAndy Fiddaman 			set_config_value_node(nvl, "vnic", name);
3232b948146SAndy Fiddaman 		}
3242b948146SAndy Fiddaman 	}
3252b948146SAndy Fiddaman 	free(tofree);
3262b948146SAndy Fiddaman 	return (0);
3272b948146SAndy Fiddaman }
3282b948146SAndy Fiddaman 
3292b948146SAndy Fiddaman static int
3302b948146SAndy Fiddaman pci_viona_parse_opts(struct pci_viona_softc *sc, nvlist_t *nvl)
3312b948146SAndy Fiddaman {
3322b948146SAndy Fiddaman 	const char *value;
333b22a70abSPatrick Mooney 	int err = 0;
334b22a70abSPatrick Mooney 
335b22a70abSPatrick Mooney 	sc->vsc_vq_size = VIONA_RINGSZ;
336b22a70abSPatrick Mooney 	sc->vsc_feature_mask = 0;
3372b948146SAndy Fiddaman 	sc->vsc_linkname[0] = '\0';
338b22a70abSPatrick Mooney 
3392b948146SAndy Fiddaman 	value = get_config_value_node(nvl, "feature_mask");
3402b948146SAndy Fiddaman 	if (value != NULL) {
341b22a70abSPatrick Mooney 		long num;
342b22a70abSPatrick Mooney 
343b22a70abSPatrick Mooney 		errno = 0;
3442b948146SAndy Fiddaman 		num = strtol(value, NULL, 0);
345b22a70abSPatrick Mooney 		if (errno != 0 || num < 0) {
346b22a70abSPatrick Mooney 			fprintf(stderr,
3472b948146SAndy Fiddaman 			    "viona: invalid mask '%s'", value);
348b22a70abSPatrick Mooney 		} else {
349b22a70abSPatrick Mooney 			sc->vsc_feature_mask = num;
350b22a70abSPatrick Mooney 		}
3512b948146SAndy Fiddaman 	}
3522b948146SAndy Fiddaman 
3532b948146SAndy Fiddaman 	value = get_config_value_node(nvl, "vqsize");
3542b948146SAndy Fiddaman 	if (value != NULL) {
355b22a70abSPatrick Mooney 		long num;
356b22a70abSPatrick Mooney 
357b22a70abSPatrick Mooney 		errno = 0;
3582b948146SAndy Fiddaman 		num = strtol(value, NULL, 0);
359b22a70abSPatrick Mooney 		if (errno != 0) {
360b22a70abSPatrick Mooney 			fprintf(stderr,
3612b948146SAndy Fiddaman 			    "viona: invalid vsqize '%s'", value);
362b22a70abSPatrick Mooney 			err = -1;
363b22a70abSPatrick Mooney 		} else if (num <= 2 || num > 32768) {
364b22a70abSPatrick Mooney 			fprintf(stderr,
365b22a70abSPatrick Mooney 			    "viona: vqsize out of range", num);
366b22a70abSPatrick Mooney 			err = -1;
367b22a70abSPatrick Mooney 		} else if ((1 << (ffs(num) - 1)) != num) {
368b22a70abSPatrick Mooney 			fprintf(stderr,
369b22a70abSPatrick Mooney 			    "viona: vqsize must be power of 2", num);
370b22a70abSPatrick Mooney 			err = -1;
371b22a70abSPatrick Mooney 		} else {
372b22a70abSPatrick Mooney 			sc->vsc_vq_size = num;
373b22a70abSPatrick Mooney 		}
374b22a70abSPatrick Mooney 	}
3752b948146SAndy Fiddaman 
3762b948146SAndy Fiddaman 	value = get_config_value_node(nvl, "vnic");
3772b948146SAndy Fiddaman 	if (value == NULL) {
378b22a70abSPatrick Mooney 		fprintf(stderr, "viona: vnic name required");
379b22a70abSPatrick Mooney 		err = -1;
380b22a70abSPatrick Mooney 	} else {
3812b948146SAndy Fiddaman 		(void) strlcpy(sc->vsc_linkname, value, MAXLINKNAMELEN);
382b22a70abSPatrick Mooney 	}
383b22a70abSPatrick Mooney 
384b22a70abSPatrick Mooney 	DPRINTF(("viona=%p dev=%s vqsize=%x feature_mask=%x\n", sc,
385b22a70abSPatrick Mooney 	    sc->vsc_linkname, sc->vsc_vq_size, sc->vsc_feature_mask));
386b22a70abSPatrick Mooney 	return (err);
387b22a70abSPatrick Mooney }
388b22a70abSPatrick Mooney 
389b22a70abSPatrick Mooney static int
3902b948146SAndy Fiddaman pci_viona_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
391bf21cd93STycho Nightingale {
392bf21cd93STycho Nightingale 	dladm_handle_t		handle;
393bf21cd93STycho Nightingale 	dladm_status_t		status;
394bf21cd93STycho Nightingale 	dladm_vnic_attr_t	attr;
395bf21cd93STycho Nightingale 	char			errmsg[DLADM_STRSIZE];
39639eba7d4SAndy Fiddaman 	char			tname[MAXCOMLEN + 1];
397b22a70abSPatrick Mooney 	int error, i;
398bf21cd93STycho Nightingale 	struct pci_viona_softc *sc;
3992b948146SAndy Fiddaman 	const char *vnic;
40039eba7d4SAndy Fiddaman 	pthread_t tid;
401bf21cd93STycho Nightingale 
4022b948146SAndy Fiddaman 	vnic = get_config_value_node(nvl, "vnic");
4032b948146SAndy Fiddaman 	if (vnic == NULL) {
404bf21cd93STycho Nightingale 		printf("virtio-viona: vnic required\n");
405bf21cd93STycho Nightingale 		return (1);
406bf21cd93STycho Nightingale 	}
407bf21cd93STycho Nightingale 
408bf21cd93STycho Nightingale 	sc = malloc(sizeof (struct pci_viona_softc));
409bf21cd93STycho Nightingale 	memset(sc, 0, sizeof (struct pci_viona_softc));
410bf21cd93STycho Nightingale 
411bf21cd93STycho Nightingale 	pi->pi_arg = sc;
412bf21cd93STycho Nightingale 	sc->vsc_pi = pi;
413bf21cd93STycho Nightingale 
414bf21cd93STycho Nightingale 	pthread_mutex_init(&sc->vsc_mtx, NULL);
415bf21cd93STycho Nightingale 
4162b948146SAndy Fiddaman 	if (pci_viona_parse_opts(sc, nvl) != 0) {
417b22a70abSPatrick Mooney 		free(sc);
418b22a70abSPatrick Mooney 		return (1);
419b22a70abSPatrick Mooney 	}
420bf21cd93STycho Nightingale 
421bf21cd93STycho Nightingale 	if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) {
422bf21cd93STycho Nightingale 		WPRINTF(("could not open /dev/dld"));
423bf21cd93STycho Nightingale 		free(sc);
424bf21cd93STycho Nightingale 		return (1);
425bf21cd93STycho Nightingale 	}
426bf21cd93STycho Nightingale 
4272b948146SAndy Fiddaman 	if ((status = dladm_name2info(handle, sc->vsc_linkname, &sc->vsc_linkid,
4282b948146SAndy Fiddaman 	    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
4292b948146SAndy Fiddaman 		WPRINTF(("dladm_name2info() for %s failed: %s\n", vnic,
430bf21cd93STycho Nightingale 		    dladm_status2str(status, errmsg)));
431bf21cd93STycho Nightingale 		dladm_close(handle);
432bf21cd93STycho Nightingale 		free(sc);
433bf21cd93STycho Nightingale 		return (1);
434bf21cd93STycho Nightingale 	}
435bf21cd93STycho Nightingale 
4362b948146SAndy Fiddaman 	if ((status = dladm_vnic_info(handle, sc->vsc_linkid, &attr,
4372b948146SAndy Fiddaman 	    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
4382b948146SAndy Fiddaman 		WPRINTF(("dladm_vnic_info() for %s failed: %s\n", vnic,
439bf21cd93STycho Nightingale 		    dladm_status2str(status, errmsg)));
440bf21cd93STycho Nightingale 		dladm_close(handle);
441bf21cd93STycho Nightingale 		free(sc);
442bf21cd93STycho Nightingale 		return (1);
443bf21cd93STycho Nightingale 	}
444bf21cd93STycho Nightingale 
445bf21cd93STycho Nightingale 	memcpy(sc->vsc_macaddr, attr.va_mac_addr, ETHERADDRL);
446bf21cd93STycho Nightingale 
447bf21cd93STycho Nightingale 	dladm_close(handle);
448bf21cd93STycho Nightingale 
449bf21cd93STycho Nightingale 	error = pci_viona_viona_init(ctx, sc);
450bf21cd93STycho Nightingale 	if (error != 0) {
451bf21cd93STycho Nightingale 		free(sc);
452bf21cd93STycho Nightingale 		return (1);
453bf21cd93STycho Nightingale 	}
454bf21cd93STycho Nightingale 
45539eba7d4SAndy Fiddaman 	error = pthread_create(&tid, NULL, pci_viona_poll_thread, sc);
456bf21cd93STycho Nightingale 	assert(error == 0);
45739eba7d4SAndy Fiddaman 	snprintf(tname, sizeof (tname), "vionapoll:%s", vnic);
45839eba7d4SAndy Fiddaman 	pthread_set_name_np(tid, tname);
459bf21cd93STycho Nightingale 
460bf21cd93STycho Nightingale 	/* initialize config space */
461bf21cd93STycho Nightingale 	pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET);
462bf21cd93STycho Nightingale 	pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
463bf21cd93STycho Nightingale 	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK);
4642b948146SAndy Fiddaman 	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_NETWORK);
465b22a70abSPatrick Mooney 	pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR);
466bf21cd93STycho Nightingale 
467bf21cd93STycho Nightingale 	/* MSI-X support */
468bf21cd93STycho Nightingale 	for (i = 0; i < VIONA_MAXQ; i++)
469bf21cd93STycho Nightingale 		sc->vsc_msix_table_idx[i] = VIRTIO_MSI_NO_VECTOR;
470bf21cd93STycho Nightingale 
471b22a70abSPatrick Mooney 	/* BAR 1 used to map MSI-X table and PBA */
472bf21cd93STycho Nightingale 	if (pci_emul_add_msixcap(pi, VIONA_MAXQ, 1)) {
473bf21cd93STycho Nightingale 		free(sc);
474bf21cd93STycho Nightingale 		return (1);
475bf21cd93STycho Nightingale 	}
476bf21cd93STycho Nightingale 
477b22a70abSPatrick Mooney 	/* BAR 0 for legacy-style virtio register access. */
478b22a70abSPatrick Mooney 	error = pci_emul_alloc_bar(pi, 0, PCIBAR_IO, VIONA_REGSZ);
479b22a70abSPatrick Mooney 	if (error != 0) {
480b22a70abSPatrick Mooney 		WPRINTF(("could not allocate virtio BAR\n"));
481b22a70abSPatrick Mooney 		free(sc);
482b22a70abSPatrick Mooney 		return (1);
483b22a70abSPatrick Mooney 	}
484bf21cd93STycho Nightingale 
485bf21cd93STycho Nightingale 	/*
486b22a70abSPatrick Mooney 	 * Need a legacy interrupt for virtio compliance, even though MSI-X
487b22a70abSPatrick Mooney 	 * operation is _strongly_ suggested for adequate performance.
488bf21cd93STycho Nightingale 	 */
489b22a70abSPatrick Mooney 	pci_lintr_request(pi);
490b22a70abSPatrick Mooney 
491b22a70abSPatrick Mooney 	return (0);
492b22a70abSPatrick Mooney }
493bf21cd93STycho Nightingale 
494bf21cd93STycho Nightingale static uint64_t
495bf21cd93STycho Nightingale viona_adjust_offset(struct pci_devinst *pi, uint64_t offset)
496bf21cd93STycho Nightingale {
497bf21cd93STycho Nightingale 	/*
498bf21cd93STycho Nightingale 	 * Device specific offsets used by guest would change based on
499bf21cd93STycho Nightingale 	 * whether MSI-X capability is enabled or not
500bf21cd93STycho Nightingale 	 */
501bf21cd93STycho Nightingale 	if (!pci_msix_enabled(pi)) {
5022b948146SAndy Fiddaman 		if (offset >= VIRTIO_PCI_CONFIG_OFF(0)) {
5032b948146SAndy Fiddaman 			return (offset + (VIRTIO_PCI_CONFIG_OFF(1) -
5042b948146SAndy Fiddaman 			    VIRTIO_PCI_CONFIG_OFF(0)));
5052b948146SAndy Fiddaman 		}
506bf21cd93STycho Nightingale 	}
507bf21cd93STycho Nightingale 
508bf21cd93STycho Nightingale 	return (offset);
509bf21cd93STycho Nightingale }
510bf21cd93STycho Nightingale 
511bf21cd93STycho Nightingale static void
512b22a70abSPatrick Mooney pci_viona_ring_set_msix(struct pci_devinst *pi, uint_t ring)
513b22a70abSPatrick Mooney {
514b22a70abSPatrick Mooney 	struct pci_viona_softc *sc = pi->pi_arg;
515b22a70abSPatrick Mooney 	struct msix_table_entry mte;
516b22a70abSPatrick Mooney 	uint16_t tab_index;
517b22a70abSPatrick Mooney 	vioc_ring_msi_t vrm;
518b22a70abSPatrick Mooney 	int res;
519b22a70abSPatrick Mooney 
520b22a70abSPatrick Mooney 	assert(ring <= VIONA_VQ_TX);
521b22a70abSPatrick Mooney 
522b22a70abSPatrick Mooney 	vrm.rm_index = ring;
523b22a70abSPatrick Mooney 	vrm.rm_addr = 0;
524b22a70abSPatrick Mooney 	vrm.rm_msg = 0;
525b22a70abSPatrick Mooney 	tab_index = sc->vsc_msix_table_idx[ring];
526b22a70abSPatrick Mooney 
527b22a70abSPatrick Mooney 	if (tab_index != VIRTIO_MSI_NO_VECTOR && sc->vsc_msix_active) {
528b22a70abSPatrick Mooney 		mte = pi->pi_msix.table[tab_index];
529b22a70abSPatrick Mooney 		if ((mte.vector_control & PCIM_MSIX_VCTRL_MASK) == 0) {
530b22a70abSPatrick Mooney 			vrm.rm_addr = mte.addr;
531b22a70abSPatrick Mooney 			vrm.rm_msg = mte.msg_data;
532b22a70abSPatrick Mooney 		}
533b22a70abSPatrick Mooney 	}
534b22a70abSPatrick Mooney 
535b22a70abSPatrick Mooney 	res = ioctl(sc->vsc_vnafd, VNA_IOC_RING_SET_MSI, &vrm);
536b22a70abSPatrick Mooney 	if (res != 0) {
537b22a70abSPatrick Mooney 		WPRINTF(("ioctl viona set_msi %d failed %d\n", ring, errno));
538b22a70abSPatrick Mooney 	}
539b22a70abSPatrick Mooney }
540b22a70abSPatrick Mooney 
541b22a70abSPatrick Mooney static void
542b22a70abSPatrick Mooney pci_viona_lintrupdate(struct pci_devinst *pi)
543b22a70abSPatrick Mooney {
544b22a70abSPatrick Mooney 	struct pci_viona_softc *sc = pi->pi_arg;
545b22a70abSPatrick Mooney 	boolean_t msix_on = B_FALSE;
546b22a70abSPatrick Mooney 
547b22a70abSPatrick Mooney 	pthread_mutex_lock(&sc->vsc_mtx);
548b22a70abSPatrick Mooney 	msix_on = pci_msix_enabled(pi) && (pi->pi_msix.function_mask == 0);
549b22a70abSPatrick Mooney 	if ((sc->vsc_msix_active && !msix_on) ||
550b22a70abSPatrick Mooney 	    (msix_on && !sc->vsc_msix_active)) {
551b22a70abSPatrick Mooney 		uint_t i;
552b22a70abSPatrick Mooney 
553b22a70abSPatrick Mooney 		sc->vsc_msix_active = msix_on;
554b22a70abSPatrick Mooney 		/* Update in-kernel ring configs */
555b22a70abSPatrick Mooney 		for (i = 0; i <= VIONA_VQ_TX; i++) {
556b22a70abSPatrick Mooney 			pci_viona_ring_set_msix(pi, i);
557b22a70abSPatrick Mooney 		}
558b22a70abSPatrick Mooney 	}
559b22a70abSPatrick Mooney 	pthread_mutex_unlock(&sc->vsc_mtx);
560b22a70abSPatrick Mooney }
561b22a70abSPatrick Mooney 
562b22a70abSPatrick Mooney static void
563b22a70abSPatrick Mooney pci_viona_msix_update(struct pci_devinst *pi, uint64_t offset)
564b22a70abSPatrick Mooney {
565b22a70abSPatrick Mooney 	struct pci_viona_softc *sc = pi->pi_arg;
566b22a70abSPatrick Mooney 	uint_t tab_index, i;
567b22a70abSPatrick Mooney 
568b22a70abSPatrick Mooney 	pthread_mutex_lock(&sc->vsc_mtx);
569b22a70abSPatrick Mooney 	if (!sc->vsc_msix_active) {
570b22a70abSPatrick Mooney 		pthread_mutex_unlock(&sc->vsc_mtx);
571b22a70abSPatrick Mooney 		return;
572b22a70abSPatrick Mooney 	}
573b22a70abSPatrick Mooney 
574b22a70abSPatrick Mooney 	/*
575b22a70abSPatrick Mooney 	 * Rather than update every possible MSI-X vector, cheat and use the
576b22a70abSPatrick Mooney 	 * offset to calculate the entry within the table.  Since this should
577b22a70abSPatrick Mooney 	 * only be called when a write to the table succeeds, the index should
578b22a70abSPatrick Mooney 	 * be valid.
579b22a70abSPatrick Mooney 	 */
580b22a70abSPatrick Mooney 	tab_index = offset / MSIX_TABLE_ENTRY_SIZE;
581b22a70abSPatrick Mooney 
582b22a70abSPatrick Mooney 	for (i = 0; i <= VIONA_VQ_TX; i++) {
583b22a70abSPatrick Mooney 		if (sc->vsc_msix_table_idx[i] != tab_index) {
584b22a70abSPatrick Mooney 			continue;
585b22a70abSPatrick Mooney 		}
586b22a70abSPatrick Mooney 		pci_viona_ring_set_msix(pi, i);
587b22a70abSPatrick Mooney 	}
588b22a70abSPatrick Mooney 
589b22a70abSPatrick Mooney 	pthread_mutex_unlock(&sc->vsc_mtx);
590b22a70abSPatrick Mooney }
591b22a70abSPatrick Mooney 
592b22a70abSPatrick Mooney static void
593b22a70abSPatrick Mooney pci_viona_qnotify(struct pci_viona_softc *sc, int ring)
594b22a70abSPatrick Mooney {
595b22a70abSPatrick Mooney 	int error;
596b22a70abSPatrick Mooney 
597b22a70abSPatrick Mooney 	switch (ring) {
598b22a70abSPatrick Mooney 	case VIONA_TXQ:
599b22a70abSPatrick Mooney 	case VIONA_RXQ:
600b22a70abSPatrick Mooney 		error = ioctl(sc->vsc_vnafd, VNA_IOC_RING_KICK, ring);
601b22a70abSPatrick Mooney 		if (error != 0) {
602b22a70abSPatrick Mooney 			WPRINTF(("ioctl viona ring %d kick failed %d\n",
603b22a70abSPatrick Mooney 			    ring, errno));
604b22a70abSPatrick Mooney 		}
605b22a70abSPatrick Mooney 		break;
606b22a70abSPatrick Mooney 	case VIONA_CTLQ:
607b22a70abSPatrick Mooney 		DPRINTF(("viona: control qnotify!\n"));
608b22a70abSPatrick Mooney 		break;
609b22a70abSPatrick Mooney 	default:
610b22a70abSPatrick Mooney 		break;
611b22a70abSPatrick Mooney 	}
612b22a70abSPatrick Mooney }
613b22a70abSPatrick Mooney 
614b22a70abSPatrick Mooney static void
615*f24fee03SAndy Fiddaman pci_viona_baraddr(struct vmctx *ctx, struct pci_devinst *pi, int baridx,
616*f24fee03SAndy Fiddaman     int enabled, uint64_t address)
617*f24fee03SAndy Fiddaman {
618*f24fee03SAndy Fiddaman 	struct pci_viona_softc *sc = pi->pi_arg;
619*f24fee03SAndy Fiddaman 	uint64_t ioport;
620*f24fee03SAndy Fiddaman 	int error;
621*f24fee03SAndy Fiddaman 
622*f24fee03SAndy Fiddaman 	if (baridx != 0)
623*f24fee03SAndy Fiddaman 		return;
624*f24fee03SAndy Fiddaman 
625*f24fee03SAndy Fiddaman 	if (enabled == 0) {
626*f24fee03SAndy Fiddaman 		error = ioctl(sc->vsc_vnafd, VNA_IOC_SET_NOTIFY_IOP, 0);
627*f24fee03SAndy Fiddaman 		if (error != 0)
628*f24fee03SAndy Fiddaman 			WPRINTF(("uninstall ioport hook failed %d\n", errno));
629*f24fee03SAndy Fiddaman 		return;
630*f24fee03SAndy Fiddaman 	}
631*f24fee03SAndy Fiddaman 
632*f24fee03SAndy Fiddaman 	/*
633*f24fee03SAndy Fiddaman 	 * Install ioport hook for virtqueue notification.
634*f24fee03SAndy Fiddaman 	 * This is part of the virtio common configuration area so the
635*f24fee03SAndy Fiddaman 	 * address does not change with MSI-X status.
636*f24fee03SAndy Fiddaman 	 */
637*f24fee03SAndy Fiddaman 	ioport = address + VIRTIO_PCI_QUEUE_NOTIFY;
638*f24fee03SAndy Fiddaman 	error = ioctl(sc->vsc_vnafd, VNA_IOC_SET_NOTIFY_IOP, ioport);
639*f24fee03SAndy Fiddaman 	if (error != 0) {
640*f24fee03SAndy Fiddaman 		WPRINTF(("install ioport hook at %x failed %d\n",
641*f24fee03SAndy Fiddaman 		    ioport, errno));
642*f24fee03SAndy Fiddaman 	}
643*f24fee03SAndy Fiddaman }
644*f24fee03SAndy Fiddaman 
645*f24fee03SAndy Fiddaman static void
646bf21cd93STycho Nightingale pci_viona_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
647bf21cd93STycho Nightingale     int baridx, uint64_t offset, int size, uint64_t value)
648bf21cd93STycho Nightingale {
649bf21cd93STycho Nightingale 	struct pci_viona_softc *sc = pi->pi_arg;
650bf21cd93STycho Nightingale 	void *ptr;
651bf21cd93STycho Nightingale 	int err = 0;
652bf21cd93STycho Nightingale 
653bf21cd93STycho Nightingale 	if (baridx == pci_msix_table_bar(pi) ||
654bf21cd93STycho Nightingale 	    baridx == pci_msix_pba_bar(pi)) {
655b22a70abSPatrick Mooney 		if (pci_emul_msix_twrite(pi, offset, size, value) == 0) {
656b22a70abSPatrick Mooney 			pci_viona_msix_update(pi, offset);
657b22a70abSPatrick Mooney 		}
658bf21cd93STycho Nightingale 		return;
659bf21cd93STycho Nightingale 	}
660bf21cd93STycho Nightingale 
661bf21cd93STycho Nightingale 	assert(baridx == 0);
662bf21cd93STycho Nightingale 
663bf21cd93STycho Nightingale 	if (offset + size > pci_viona_iosize(pi)) {
664bf21cd93STycho Nightingale 		DPRINTF(("viona_write: 2big, offset %ld size %d\n",
665bf21cd93STycho Nightingale 		    offset, size));
666bf21cd93STycho Nightingale 		return;
667bf21cd93STycho Nightingale 	}
668bf21cd93STycho Nightingale 
669bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->vsc_mtx);
670bf21cd93STycho Nightingale 
671bf21cd93STycho Nightingale 	offset = viona_adjust_offset(pi, offset);
672bf21cd93STycho Nightingale 
673bf21cd93STycho Nightingale 	switch (offset) {
6742b948146SAndy Fiddaman 	case VIRTIO_PCI_GUEST_FEATURES:
675bf21cd93STycho Nightingale 		assert(size == 4);
676b22a70abSPatrick Mooney 		value &= ~(sc->vsc_feature_mask);
677bf21cd93STycho Nightingale 		err = ioctl(sc->vsc_vnafd, VNA_IOC_SET_FEATURES, &value);
678b22a70abSPatrick Mooney 		if (err != 0) {
679bf21cd93STycho Nightingale 			WPRINTF(("ioctl feature negotiation returned"
680b22a70abSPatrick Mooney 			    " err = %d\n", errno));
681b22a70abSPatrick Mooney 		} else {
682b22a70abSPatrick Mooney 			sc->vsc_features = value;
683b22a70abSPatrick Mooney 		}
684bf21cd93STycho Nightingale 		break;
6852b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_PFN:
686bf21cd93STycho Nightingale 		assert(size == 4);
687bf21cd93STycho Nightingale 		pci_viona_ring_init(sc, value);
688bf21cd93STycho Nightingale 		break;
6892b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_SEL:
690bf21cd93STycho Nightingale 		assert(size == 2);
691bf21cd93STycho Nightingale 		assert(value < VIONA_MAXQ);
692bf21cd93STycho Nightingale 		sc->vsc_curq = value;
693bf21cd93STycho Nightingale 		break;
6942b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_NOTIFY:
695bf21cd93STycho Nightingale 		assert(size == 2);
696bf21cd93STycho Nightingale 		assert(value < VIONA_MAXQ);
697b22a70abSPatrick Mooney 		pci_viona_qnotify(sc, value);
698bf21cd93STycho Nightingale 		break;
6992b948146SAndy Fiddaman 	case VIRTIO_PCI_STATUS:
700bf21cd93STycho Nightingale 		assert(size == 1);
701bf21cd93STycho Nightingale 		pci_viona_update_status(sc, value);
702bf21cd93STycho Nightingale 		break;
7032b948146SAndy Fiddaman 	case VIRTIO_MSI_CONFIG_VECTOR:
704bf21cd93STycho Nightingale 		assert(size == 2);
705bf21cd93STycho Nightingale 		sc->vsc_msix_table_idx[VIONA_CTLQ] = value;
706bf21cd93STycho Nightingale 		break;
7072b948146SAndy Fiddaman 	case VIRTIO_MSI_QUEUE_VECTOR:
708bf21cd93STycho Nightingale 		assert(size == 2);
709bf21cd93STycho Nightingale 		assert(sc->vsc_curq != VIONA_CTLQ);
710bf21cd93STycho Nightingale 		sc->vsc_msix_table_idx[sc->vsc_curq] = value;
711b22a70abSPatrick Mooney 		pci_viona_ring_set_msix(pi, sc->vsc_curq);
712bf21cd93STycho Nightingale 		break;
713bf21cd93STycho Nightingale 	case VIONA_R_CFG0:
714bf21cd93STycho Nightingale 	case VIONA_R_CFG1:
715bf21cd93STycho Nightingale 	case VIONA_R_CFG2:
716bf21cd93STycho Nightingale 	case VIONA_R_CFG3:
717bf21cd93STycho Nightingale 	case VIONA_R_CFG4:
718bf21cd93STycho Nightingale 	case VIONA_R_CFG5:
719bf21cd93STycho Nightingale 		assert((size + offset) <= (VIONA_R_CFG5 + 1));
720bf21cd93STycho Nightingale 		ptr = &sc->vsc_macaddr[offset - VIONA_R_CFG0];
721bf21cd93STycho Nightingale 		/*
722bf21cd93STycho Nightingale 		 * The driver is allowed to change the MAC address
723bf21cd93STycho Nightingale 		 */
724bf21cd93STycho Nightingale 		sc->vsc_macaddr[offset - VIONA_R_CFG0] = value;
725bf21cd93STycho Nightingale 		if (size == 1) {
726bf21cd93STycho Nightingale 			*(uint8_t *)ptr = value;
727bf21cd93STycho Nightingale 		} else if (size == 2) {
728bf21cd93STycho Nightingale 			*(uint16_t *)ptr = value;
729bf21cd93STycho Nightingale 		} else {
730bf21cd93STycho Nightingale 			*(uint32_t *)ptr = value;
731bf21cd93STycho Nightingale 		}
732bf21cd93STycho Nightingale 		break;
7332b948146SAndy Fiddaman 	case VIRTIO_PCI_HOST_FEATURES:
7342b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_NUM:
7352b948146SAndy Fiddaman 	case VIRTIO_PCI_ISR:
736bf21cd93STycho Nightingale 	case VIONA_R_CFG6:
737bf21cd93STycho Nightingale 	case VIONA_R_CFG7:
738bf21cd93STycho Nightingale 		DPRINTF(("viona: write to readonly reg %ld\n\r", offset));
739bf21cd93STycho Nightingale 		break;
740bf21cd93STycho Nightingale 	default:
741bf21cd93STycho Nightingale 		DPRINTF(("viona: unknown i/o write offset %ld\n\r", offset));
742bf21cd93STycho Nightingale 		value = 0;
743bf21cd93STycho Nightingale 		break;
744bf21cd93STycho Nightingale 	}
745bf21cd93STycho Nightingale 
746bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->vsc_mtx);
747bf21cd93STycho Nightingale }
748bf21cd93STycho Nightingale 
749b22a70abSPatrick Mooney static uint64_t
750bf21cd93STycho Nightingale pci_viona_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
751bf21cd93STycho Nightingale     int baridx, uint64_t offset, int size)
752bf21cd93STycho Nightingale {
753bf21cd93STycho Nightingale 	struct pci_viona_softc *sc = pi->pi_arg;
754bf21cd93STycho Nightingale 	void *ptr;
755bf21cd93STycho Nightingale 	uint64_t value;
756bf21cd93STycho Nightingale 	int err = 0;
757bf21cd93STycho Nightingale 
758bf21cd93STycho Nightingale 	if (baridx == pci_msix_table_bar(pi) ||
759bf21cd93STycho Nightingale 	    baridx == pci_msix_pba_bar(pi)) {
760bf21cd93STycho Nightingale 		return (pci_emul_msix_tread(pi, offset, size));
761bf21cd93STycho Nightingale 	}
762bf21cd93STycho Nightingale 
763bf21cd93STycho Nightingale 	assert(baridx == 0);
764bf21cd93STycho Nightingale 
765bf21cd93STycho Nightingale 	if (offset + size > pci_viona_iosize(pi)) {
766bf21cd93STycho Nightingale 		DPRINTF(("viona_read: 2big, offset %ld size %d\n",
767bf21cd93STycho Nightingale 		    offset, size));
768bf21cd93STycho Nightingale 		return (0);
769bf21cd93STycho Nightingale 	}
770bf21cd93STycho Nightingale 
771bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->vsc_mtx);
772bf21cd93STycho Nightingale 
773bf21cd93STycho Nightingale 	offset = viona_adjust_offset(pi, offset);
774bf21cd93STycho Nightingale 
775bf21cd93STycho Nightingale 	switch (offset) {
7762b948146SAndy Fiddaman 	case VIRTIO_PCI_HOST_FEATURES:
777bf21cd93STycho Nightingale 		assert(size == 4);
778bf21cd93STycho Nightingale 		err = ioctl(sc->vsc_vnafd, VNA_IOC_GET_FEATURES, &value);
779b22a70abSPatrick Mooney 		if (err != 0) {
780bf21cd93STycho Nightingale 			WPRINTF(("ioctl get host features returned"
781b22a70abSPatrick Mooney 			    " err = %d\n", errno));
782b22a70abSPatrick Mooney 		}
783b22a70abSPatrick Mooney 		value &= ~sc->vsc_feature_mask;
784bf21cd93STycho Nightingale 		break;
7852b948146SAndy Fiddaman 	case VIRTIO_PCI_GUEST_FEATURES:
786bf21cd93STycho Nightingale 		assert(size == 4);
787bf21cd93STycho Nightingale 		value = sc->vsc_features; /* XXX never read ? */
788bf21cd93STycho Nightingale 		break;
7892b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_PFN:
790bf21cd93STycho Nightingale 		assert(size == 4);
791bf21cd93STycho Nightingale 		value = sc->vsc_pfn[sc->vsc_curq] >> VRING_PFN;
792bf21cd93STycho Nightingale 		break;
7932b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_NUM:
794bf21cd93STycho Nightingale 		assert(size == 2);
795b22a70abSPatrick Mooney 		value = pci_viona_qsize(sc, sc->vsc_curq);
796bf21cd93STycho Nightingale 		break;
7972b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_SEL:
798bf21cd93STycho Nightingale 		assert(size == 2);
799bf21cd93STycho Nightingale 		value = sc->vsc_curq;  /* XXX never read ? */
800bf21cd93STycho Nightingale 		break;
8012b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_NOTIFY:
802bf21cd93STycho Nightingale 		assert(size == 2);
803bf21cd93STycho Nightingale 		value = sc->vsc_curq;  /* XXX never read ? */
804bf21cd93STycho Nightingale 		break;
8052b948146SAndy Fiddaman 	case VIRTIO_PCI_STATUS:
806bf21cd93STycho Nightingale 		assert(size == 1);
807bf21cd93STycho Nightingale 		value = sc->vsc_status;
808bf21cd93STycho Nightingale 		break;
8092b948146SAndy Fiddaman 	case VIRTIO_PCI_ISR:
810bf21cd93STycho Nightingale 		assert(size == 1);
811bf21cd93STycho Nightingale 		value = sc->vsc_isr;
812bf21cd93STycho Nightingale 		sc->vsc_isr = 0;	/* a read clears this flag */
813b22a70abSPatrick Mooney 		if (value != 0) {
814b22a70abSPatrick Mooney 			pci_lintr_deassert(pi);
815b22a70abSPatrick Mooney 		}
816bf21cd93STycho Nightingale 		break;
8172b948146SAndy Fiddaman 	case VIRTIO_MSI_CONFIG_VECTOR:
818bf21cd93STycho Nightingale 		assert(size == 2);
819bf21cd93STycho Nightingale 		value = sc->vsc_msix_table_idx[VIONA_CTLQ];
820bf21cd93STycho Nightingale 		break;
8212b948146SAndy Fiddaman 	case VIRTIO_MSI_QUEUE_VECTOR:
822bf21cd93STycho Nightingale 		assert(size == 2);
823bf21cd93STycho Nightingale 		assert(sc->vsc_curq != VIONA_CTLQ);
824bf21cd93STycho Nightingale 		value = sc->vsc_msix_table_idx[sc->vsc_curq];
825bf21cd93STycho Nightingale 		break;
826bf21cd93STycho Nightingale 	case VIONA_R_CFG0:
827bf21cd93STycho Nightingale 	case VIONA_R_CFG1:
828bf21cd93STycho Nightingale 	case VIONA_R_CFG2:
829bf21cd93STycho Nightingale 	case VIONA_R_CFG3:
830bf21cd93STycho Nightingale 	case VIONA_R_CFG4:
831bf21cd93STycho Nightingale 	case VIONA_R_CFG5:
832bf21cd93STycho Nightingale 		assert((size + offset) <= (VIONA_R_CFG5 + 1));
833bf21cd93STycho Nightingale 		ptr = &sc->vsc_macaddr[offset - VIONA_R_CFG0];
834bf21cd93STycho Nightingale 		if (size == 1) {
835bf21cd93STycho Nightingale 			value = *(uint8_t *)ptr;
836bf21cd93STycho Nightingale 		} else if (size == 2) {
837bf21cd93STycho Nightingale 			value = *(uint16_t *)ptr;
838bf21cd93STycho Nightingale 		} else {
839bf21cd93STycho Nightingale 			value = *(uint32_t *)ptr;
840bf21cd93STycho Nightingale 		}
841bf21cd93STycho Nightingale 		break;
842bf21cd93STycho Nightingale 	case VIONA_R_CFG6:
843bf21cd93STycho Nightingale 		assert(size != 4);
844bf21cd93STycho Nightingale 		value = 0x01;	/* XXX link always up */
845bf21cd93STycho Nightingale 		break;
846bf21cd93STycho Nightingale 	case VIONA_R_CFG7:
847bf21cd93STycho Nightingale 		assert(size == 1);
848bf21cd93STycho Nightingale 		value = 0;	/* XXX link status in LSB */
849bf21cd93STycho Nightingale 		break;
850bf21cd93STycho Nightingale 	default:
851bf21cd93STycho Nightingale 		DPRINTF(("viona: unknown i/o read offset %ld\n\r", offset));
852bf21cd93STycho Nightingale 		value = 0;
853bf21cd93STycho Nightingale 		break;
854bf21cd93STycho Nightingale 	}
855bf21cd93STycho Nightingale 
856bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->vsc_mtx);
857bf21cd93STycho Nightingale 
858bf21cd93STycho Nightingale 	return (value);
859bf21cd93STycho Nightingale }
860bf21cd93STycho Nightingale 
861bf21cd93STycho Nightingale struct pci_devemu pci_de_viona = {
862bf21cd93STycho Nightingale 	.pe_emu =	"virtio-net-viona",
863bf21cd93STycho Nightingale 	.pe_init =	pci_viona_init,
8642b948146SAndy Fiddaman 	.pe_legacy_config = pci_viona_legacy_config,
865bf21cd93STycho Nightingale 	.pe_barwrite =	pci_viona_write,
866b22a70abSPatrick Mooney 	.pe_barread =	pci_viona_read,
867*f24fee03SAndy Fiddaman 	.pe_baraddr =	pci_viona_baraddr,
868b22a70abSPatrick Mooney 	.pe_lintrupdate = pci_viona_lintrupdate
869bf21cd93STycho Nightingale };
870bf21cd93STycho Nightingale PCI_EMUL_SET(pci_de_viona);
871