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.
38bf21cd93STycho Nightingale  */
39bf21cd93STycho Nightingale 
40bf21cd93STycho Nightingale #include <sys/cdefs.h>
41bf21cd93STycho Nightingale 
42bf21cd93STycho Nightingale #include <sys/param.h>
43bf21cd93STycho Nightingale #include <sys/linker_set.h>
44bf21cd93STycho Nightingale #include <sys/ioctl.h>
45bf21cd93STycho Nightingale #include <sys/viona_io.h>
46bf21cd93STycho Nightingale 
47bf21cd93STycho Nightingale #include <errno.h>
48bf21cd93STycho Nightingale #include <fcntl.h>
49bf21cd93STycho Nightingale #include <stdio.h>
50bf21cd93STycho Nightingale #include <stdlib.h>
51bf21cd93STycho Nightingale #include <stdint.h>
52bf21cd93STycho Nightingale #include <string.h>
53bf21cd93STycho Nightingale #include <strings.h>
54bf21cd93STycho Nightingale #include <unistd.h>
55bf21cd93STycho Nightingale #include <assert.h>
56bf21cd93STycho Nightingale #include <pthread.h>
57bf21cd93STycho Nightingale #include <signal.h>
58bf21cd93STycho Nightingale #include <poll.h>
59bf21cd93STycho Nightingale #include <libdladm.h>
60bf21cd93STycho Nightingale #include <libdllink.h>
61bf21cd93STycho Nightingale #include <libdlvnic.h>
62bf21cd93STycho Nightingale 
63bf21cd93STycho Nightingale #include <machine/vmm.h>
64bf21cd93STycho Nightingale #include <vmmapi.h>
65bf21cd93STycho Nightingale 
66bf21cd93STycho Nightingale #include "bhyverun.h"
672b948146SAndy Fiddaman #include "config.h"
68bf21cd93STycho Nightingale #include "pci_emul.h"
69bf21cd93STycho Nightingale #include "virtio.h"
70bf21cd93STycho Nightingale 
71bf21cd93STycho Nightingale #define	VIONA_RINGSZ	1024
72bf21cd93STycho Nightingale 
73bf21cd93STycho Nightingale /*
74bf21cd93STycho Nightingale  * PCI config-space register offsets
75bf21cd93STycho Nightingale  */
76bf21cd93STycho Nightingale #define	VIONA_R_CFG0	24
77bf21cd93STycho Nightingale #define	VIONA_R_CFG1	25
78bf21cd93STycho Nightingale #define	VIONA_R_CFG2	26
79bf21cd93STycho Nightingale #define	VIONA_R_CFG3	27
80bf21cd93STycho Nightingale #define	VIONA_R_CFG4	28
81bf21cd93STycho Nightingale #define	VIONA_R_CFG5	29
82bf21cd93STycho Nightingale #define	VIONA_R_CFG6	30
83bf21cd93STycho Nightingale #define	VIONA_R_CFG7	31
84bf21cd93STycho Nightingale #define	VIONA_R_MAX	31
85bf21cd93STycho Nightingale 
86bf21cd93STycho Nightingale #define	VIONA_REGSZ	VIONA_R_MAX+1
87bf21cd93STycho Nightingale 
88bf21cd93STycho Nightingale /*
89bf21cd93STycho Nightingale  * Queue definitions.
90bf21cd93STycho Nightingale  */
91bf21cd93STycho Nightingale #define	VIONA_RXQ	0
92bf21cd93STycho Nightingale #define	VIONA_TXQ	1
93bf21cd93STycho Nightingale #define	VIONA_CTLQ	2
94bf21cd93STycho Nightingale 
95bf21cd93STycho Nightingale #define	VIONA_MAXQ	3
96bf21cd93STycho Nightingale 
97bf21cd93STycho Nightingale /*
98bf21cd93STycho Nightingale  * Debug printf
99bf21cd93STycho Nightingale  */
100b22a70abSPatrick Mooney static volatile int pci_viona_debug;
101bf21cd93STycho Nightingale #define	DPRINTF(params) if (pci_viona_debug) printf params
102bf21cd93STycho Nightingale #define	WPRINTF(params) printf params
103bf21cd93STycho Nightingale 
104bf21cd93STycho Nightingale /*
105bf21cd93STycho Nightingale  * Per-device softc
106bf21cd93STycho Nightingale  */
107bf21cd93STycho Nightingale struct pci_viona_softc {
108bf21cd93STycho Nightingale 	struct pci_devinst *vsc_pi;
109bf21cd93STycho Nightingale 	pthread_mutex_t vsc_mtx;
110bf21cd93STycho Nightingale 
111bf21cd93STycho Nightingale 	int		vsc_curq;
112bf21cd93STycho Nightingale 	int		vsc_status;
113bf21cd93STycho Nightingale 	int		vsc_isr;
114bf21cd93STycho Nightingale 
115bf21cd93STycho Nightingale 	datalink_id_t	vsc_linkid;
116bf21cd93STycho Nightingale 	int		vsc_vnafd;
117bf21cd93STycho Nightingale 
118b22a70abSPatrick Mooney 	/* Configurable parameters */
119b22a70abSPatrick Mooney 	char		vsc_linkname[MAXLINKNAMELEN];
120b22a70abSPatrick Mooney 	uint32_t	vsc_feature_mask;
121b22a70abSPatrick Mooney 	uint16_t	vsc_vq_size;
122b22a70abSPatrick Mooney 
123bf21cd93STycho Nightingale 	uint32_t	vsc_features;
124bf21cd93STycho Nightingale 	uint8_t		vsc_macaddr[6];
125bf21cd93STycho Nightingale 
126bf21cd93STycho Nightingale 	uint64_t	vsc_pfn[VIONA_MAXQ];
127bf21cd93STycho Nightingale 	uint16_t	vsc_msix_table_idx[VIONA_MAXQ];
128b22a70abSPatrick Mooney 	boolean_t	vsc_msix_active;
129bf21cd93STycho Nightingale };
130bf21cd93STycho Nightingale 
131bf21cd93STycho Nightingale /*
132bf21cd93STycho Nightingale  * Return the size of IO BAR that maps virtio header and device specific
133bf21cd93STycho Nightingale  * region. The size would vary depending on whether MSI-X is enabled or
134bf21cd93STycho Nightingale  * not.
135bf21cd93STycho Nightingale  */
136bf21cd93STycho Nightingale static uint64_t
137bf21cd93STycho Nightingale pci_viona_iosize(struct pci_devinst *pi)
138bf21cd93STycho Nightingale {
1392b948146SAndy Fiddaman 	if (pci_msix_enabled(pi)) {
140bf21cd93STycho Nightingale 		return (VIONA_REGSZ);
1412b948146SAndy Fiddaman 	} else {
1422b948146SAndy Fiddaman 		return (VIONA_REGSZ -
1432b948146SAndy Fiddaman 		    (VIRTIO_PCI_CONFIG_OFF(1) - VIRTIO_PCI_CONFIG_OFF(0)));
1442b948146SAndy Fiddaman 	}
145bf21cd93STycho Nightingale }
146bf21cd93STycho Nightingale 
147bf21cd93STycho Nightingale static uint16_t
148b22a70abSPatrick Mooney pci_viona_qsize(struct pci_viona_softc *sc, int qnum)
149bf21cd93STycho Nightingale {
150bf21cd93STycho Nightingale 	/* XXX no ctl queue currently */
151bf21cd93STycho Nightingale 	if (qnum == VIONA_CTLQ) {
152bf21cd93STycho Nightingale 		return (0);
153bf21cd93STycho Nightingale 	}
154bf21cd93STycho Nightingale 
155b22a70abSPatrick Mooney 	return (sc->vsc_vq_size);
156bf21cd93STycho Nightingale }
157bf21cd93STycho Nightingale 
158bf21cd93STycho Nightingale static void
159bf21cd93STycho Nightingale pci_viona_ring_reset(struct pci_viona_softc *sc, int ring)
160bf21cd93STycho Nightingale {
161bf21cd93STycho Nightingale 	assert(ring < VIONA_MAXQ);
162bf21cd93STycho Nightingale 
163bf21cd93STycho Nightingale 	switch (ring) {
164bf21cd93STycho Nightingale 	case VIONA_RXQ:
165bf21cd93STycho Nightingale 	case VIONA_TXQ:
166bf21cd93STycho Nightingale 		break;
167bf21cd93STycho Nightingale 	case VIONA_CTLQ:
168bf21cd93STycho Nightingale 	default:
169b22a70abSPatrick Mooney 		return;
170bf21cd93STycho Nightingale 	}
171b22a70abSPatrick Mooney 
172b22a70abSPatrick Mooney 	for (;;) {
173b22a70abSPatrick Mooney 		int res;
174b22a70abSPatrick Mooney 
175b22a70abSPatrick Mooney 		res = ioctl(sc->vsc_vnafd, VNA_IOC_RING_RESET, ring);
176b22a70abSPatrick Mooney 		if (res == 0) {
177b22a70abSPatrick Mooney 			break;
178b22a70abSPatrick Mooney 		} else if (errno != EINTR) {
179b22a70abSPatrick Mooney 			WPRINTF(("ioctl viona ring %d reset failed %d\n",
180b22a70abSPatrick Mooney 			    ring, errno));
181b22a70abSPatrick Mooney 			return;
182b22a70abSPatrick Mooney 		}
183b22a70abSPatrick Mooney 	}
184b22a70abSPatrick Mooney 
185b22a70abSPatrick Mooney 	sc->vsc_pfn[ring] = 0;
186bf21cd93STycho Nightingale }
187bf21cd93STycho Nightingale 
188bf21cd93STycho Nightingale static void
189bf21cd93STycho Nightingale pci_viona_update_status(struct pci_viona_softc *sc, uint32_t value)
190bf21cd93STycho Nightingale {
191bf21cd93STycho Nightingale 
192bf21cd93STycho Nightingale 	if (value == 0) {
193bf21cd93STycho Nightingale 		DPRINTF(("viona: device reset requested !\n"));
194bf21cd93STycho Nightingale 		pci_viona_ring_reset(sc, VIONA_RXQ);
195bf21cd93STycho Nightingale 		pci_viona_ring_reset(sc, VIONA_TXQ);
196bf21cd93STycho Nightingale 	}
197bf21cd93STycho Nightingale 
198bf21cd93STycho Nightingale 	sc->vsc_status = value;
199bf21cd93STycho Nightingale }
200bf21cd93STycho Nightingale 
201bf21cd93STycho Nightingale static void *
202bf21cd93STycho Nightingale pci_viona_poll_thread(void *param)
203bf21cd93STycho Nightingale {
204bf21cd93STycho Nightingale 	struct pci_viona_softc *sc = param;
205bf21cd93STycho Nightingale 	pollfd_t pollset;
206b22a70abSPatrick Mooney 	const int fd = sc->vsc_vnafd;
207bf21cd93STycho Nightingale 
208b22a70abSPatrick Mooney 	pollset.fd = fd;
209b22a70abSPatrick Mooney 	pollset.events = POLLRDBAND;
210bf21cd93STycho Nightingale 
211bf21cd93STycho Nightingale 	for (;;) {
212bf21cd93STycho Nightingale 		if (poll(&pollset, 1, -1) < 0) {
213bf21cd93STycho Nightingale 			if (errno == EINTR || errno == EAGAIN) {
214bf21cd93STycho Nightingale 				continue;
215bf21cd93STycho Nightingale 			} else {
216bf21cd93STycho Nightingale 				WPRINTF(("pci_viona_poll_thread poll()"
217bf21cd93STycho Nightingale 				    "error %d\n", errno));
218bf21cd93STycho Nightingale 				break;
219bf21cd93STycho Nightingale 			}
220bf21cd93STycho Nightingale 		}
221b22a70abSPatrick Mooney 		if (pollset.revents & POLLRDBAND) {
222b22a70abSPatrick Mooney 			vioc_intr_poll_t vip;
223b22a70abSPatrick Mooney 			uint_t i;
224b22a70abSPatrick Mooney 			int res;
225b22a70abSPatrick Mooney 			boolean_t assert_lintr = B_FALSE;
226b22a70abSPatrick Mooney 			const boolean_t do_msix = pci_msix_enabled(sc->vsc_pi);
227bf21cd93STycho Nightingale 
228b22a70abSPatrick Mooney 			res = ioctl(fd, VNA_IOC_INTR_POLL, &vip);
229b22a70abSPatrick Mooney 			for (i = 0; res > 0 && i < VIONA_VQ_MAX; i++) {
230b22a70abSPatrick Mooney 				if (vip.vip_status[i] == 0) {
231b22a70abSPatrick Mooney 					continue;
232b22a70abSPatrick Mooney 				}
233b22a70abSPatrick Mooney 				if (do_msix) {
234bf21cd93STycho Nightingale 					pci_generate_msix(sc->vsc_pi,
235b22a70abSPatrick Mooney 					    sc->vsc_msix_table_idx[i]);
236b22a70abSPatrick Mooney 				} else {
237b22a70abSPatrick Mooney 					assert_lintr = B_TRUE;
238b22a70abSPatrick Mooney 				}
239b22a70abSPatrick Mooney 				res = ioctl(fd, VNA_IOC_RING_INTR_CLR, i);
240b22a70abSPatrick Mooney 				if (res != 0) {
241b22a70abSPatrick Mooney 					WPRINTF(("ioctl viona vq %d intr "
242b22a70abSPatrick Mooney 					    "clear failed %d\n", i, errno));
243b22a70abSPatrick Mooney 				}
244b22a70abSPatrick Mooney 			}
245b22a70abSPatrick Mooney 			if (assert_lintr) {
246b22a70abSPatrick Mooney 				pthread_mutex_lock(&sc->vsc_mtx);
247b22a70abSPatrick Mooney 				sc->vsc_isr |= VTCFG_ISR_QUEUES;
248b22a70abSPatrick Mooney 				pci_lintr_assert(sc->vsc_pi);
249b22a70abSPatrick Mooney 				pthread_mutex_unlock(&sc->vsc_mtx);
250bf21cd93STycho Nightingale 			}
251bf21cd93STycho Nightingale 		}
252bf21cd93STycho Nightingale 	}
253bf21cd93STycho Nightingale 
254bf21cd93STycho Nightingale 	pthread_exit(NULL);
255bf21cd93STycho Nightingale }
256bf21cd93STycho Nightingale 
257bf21cd93STycho Nightingale static void
258bf21cd93STycho Nightingale pci_viona_ring_init(struct pci_viona_softc *sc, uint64_t pfn)
259bf21cd93STycho Nightingale {
260bf21cd93STycho Nightingale 	int			qnum = sc->vsc_curq;
261bf21cd93STycho Nightingale 	vioc_ring_init_t	vna_ri;
262bf21cd93STycho Nightingale 	int			error;
263bf21cd93STycho Nightingale 
264bf21cd93STycho Nightingale 	assert(qnum < VIONA_MAXQ);
265bf21cd93STycho Nightingale 
266b22a70abSPatrick Mooney 	if (qnum == VIONA_CTLQ) {
267b22a70abSPatrick Mooney 		return;
268b22a70abSPatrick Mooney 	}
269b22a70abSPatrick Mooney 
270bf21cd93STycho Nightingale 	sc->vsc_pfn[qnum] = (pfn << VRING_PFN);
271bf21cd93STycho Nightingale 
272b22a70abSPatrick Mooney 	vna_ri.ri_index = qnum;
273b22a70abSPatrick Mooney 	vna_ri.ri_qsize = pci_viona_qsize(sc, qnum);
274bf21cd93STycho Nightingale 	vna_ri.ri_qaddr = (pfn << VRING_PFN);
275b22a70abSPatrick Mooney 	error = ioctl(sc->vsc_vnafd, VNA_IOC_RING_INIT, &vna_ri);
276bf21cd93STycho Nightingale 
277bf21cd93STycho Nightingale 	if (error != 0) {
278b22a70abSPatrick Mooney 		WPRINTF(("ioctl viona ring %u init failed %d\n", qnum, errno));
279bf21cd93STycho Nightingale 	}
280bf21cd93STycho Nightingale }
281bf21cd93STycho Nightingale 
282bf21cd93STycho Nightingale static int
283bf21cd93STycho Nightingale pci_viona_viona_init(struct vmctx *ctx, struct pci_viona_softc *sc)
284bf21cd93STycho Nightingale {
285bf21cd93STycho Nightingale 	vioc_create_t		vna_create;
286bf21cd93STycho Nightingale 	int			error;
287bf21cd93STycho Nightingale 
288b22a70abSPatrick Mooney 	sc->vsc_vnafd = open("/dev/viona", O_RDWR | O_EXCL);
289bf21cd93STycho Nightingale 	if (sc->vsc_vnafd == -1) {
290b22a70abSPatrick Mooney 		WPRINTF(("open viona ctl failed: %d\n", errno));
291bf21cd93STycho Nightingale 		return (-1);
292bf21cd93STycho Nightingale 	}
293bf21cd93STycho Nightingale 
294bf21cd93STycho Nightingale 	vna_create.c_linkid = sc->vsc_linkid;
295b22a70abSPatrick Mooney 	vna_create.c_vmfd = vm_get_device_fd(ctx);
296bf21cd93STycho Nightingale 	error = ioctl(sc->vsc_vnafd, VNA_IOC_CREATE, &vna_create);
297bf21cd93STycho Nightingale 	if (error != 0) {
298b22a70abSPatrick Mooney 		(void) close(sc->vsc_vnafd);
299b22a70abSPatrick Mooney 		WPRINTF(("ioctl viona create failed %d\n", errno));
300bf21cd93STycho Nightingale 		return (-1);
301bf21cd93STycho Nightingale 	}
302bf21cd93STycho Nightingale 
303bf21cd93STycho Nightingale 	return (0);
304bf21cd93STycho Nightingale }
305bf21cd93STycho Nightingale 
306bf21cd93STycho Nightingale static int
3072b948146SAndy Fiddaman pci_viona_legacy_config(nvlist_t *nvl, const char *opt)
308b22a70abSPatrick Mooney {
3092b948146SAndy Fiddaman 	char *config, *name, *tofree, *value;
3102b948146SAndy Fiddaman 
3112b948146SAndy Fiddaman 	if (opt == NULL)
3122b948146SAndy Fiddaman 		return (0);
3132b948146SAndy Fiddaman 
3142b948146SAndy Fiddaman 	config = tofree = strdup(opt);
3152b948146SAndy Fiddaman 	while ((name = strsep(&config, ",")) != NULL) {
3162b948146SAndy Fiddaman 		value = strchr(name, '=');
3172b948146SAndy Fiddaman 		if (value != NULL) {
3182b948146SAndy Fiddaman 			*value++ = '\0';
3192b948146SAndy Fiddaman 			set_config_value_node(nvl, name, value);
3202b948146SAndy Fiddaman 		} else {
3212b948146SAndy Fiddaman 			set_config_value_node(nvl, "vnic", name);
3222b948146SAndy Fiddaman 		}
3232b948146SAndy Fiddaman 	}
3242b948146SAndy Fiddaman 	free(tofree);
3252b948146SAndy Fiddaman 	return (0);
3262b948146SAndy Fiddaman }
3272b948146SAndy Fiddaman 
3282b948146SAndy Fiddaman static int
3292b948146SAndy Fiddaman pci_viona_parse_opts(struct pci_viona_softc *sc, nvlist_t *nvl)
3302b948146SAndy Fiddaman {
3312b948146SAndy Fiddaman 	const char *value;
332b22a70abSPatrick Mooney 	int err = 0;
333b22a70abSPatrick Mooney 
334b22a70abSPatrick Mooney 	sc->vsc_vq_size = VIONA_RINGSZ;
335b22a70abSPatrick Mooney 	sc->vsc_feature_mask = 0;
3362b948146SAndy Fiddaman 	sc->vsc_linkname[0] = '\0';
337b22a70abSPatrick Mooney 
3382b948146SAndy Fiddaman 	value = get_config_value_node(nvl, "feature_mask");
3392b948146SAndy Fiddaman 	if (value != NULL) {
340b22a70abSPatrick Mooney 		long num;
341b22a70abSPatrick Mooney 
342b22a70abSPatrick Mooney 		errno = 0;
3432b948146SAndy Fiddaman 		num = strtol(value, NULL, 0);
344b22a70abSPatrick Mooney 		if (errno != 0 || num < 0) {
345b22a70abSPatrick Mooney 			fprintf(stderr,
3462b948146SAndy Fiddaman 			    "viona: invalid mask '%s'", value);
347b22a70abSPatrick Mooney 		} else {
348b22a70abSPatrick Mooney 			sc->vsc_feature_mask = num;
349b22a70abSPatrick Mooney 		}
3502b948146SAndy Fiddaman 	}
3512b948146SAndy Fiddaman 
3522b948146SAndy Fiddaman 	value = get_config_value_node(nvl, "vqsize");
3532b948146SAndy Fiddaman 	if (value != NULL) {
354b22a70abSPatrick Mooney 		long num;
355b22a70abSPatrick Mooney 
356b22a70abSPatrick Mooney 		errno = 0;
3572b948146SAndy Fiddaman 		num = strtol(value, NULL, 0);
358b22a70abSPatrick Mooney 		if (errno != 0) {
359b22a70abSPatrick Mooney 			fprintf(stderr,
3602b948146SAndy Fiddaman 			    "viona: invalid vsqize '%s'", value);
361b22a70abSPatrick Mooney 			err = -1;
362b22a70abSPatrick Mooney 		} else if (num <= 2 || num > 32768) {
363b22a70abSPatrick Mooney 			fprintf(stderr,
364b22a70abSPatrick Mooney 			    "viona: vqsize out of range", num);
365b22a70abSPatrick Mooney 			err = -1;
366b22a70abSPatrick Mooney 		} else if ((1 << (ffs(num) - 1)) != num) {
367b22a70abSPatrick Mooney 			fprintf(stderr,
368b22a70abSPatrick Mooney 			    "viona: vqsize must be power of 2", num);
369b22a70abSPatrick Mooney 			err = -1;
370b22a70abSPatrick Mooney 		} else {
371b22a70abSPatrick Mooney 			sc->vsc_vq_size = num;
372b22a70abSPatrick Mooney 		}
373b22a70abSPatrick Mooney 	}
3742b948146SAndy Fiddaman 
3752b948146SAndy Fiddaman 	value = get_config_value_node(nvl, "vnic");
3762b948146SAndy Fiddaman 	if (value == NULL) {
377b22a70abSPatrick Mooney 		fprintf(stderr, "viona: vnic name required");
378b22a70abSPatrick Mooney 		err = -1;
379b22a70abSPatrick Mooney 	} else {
3802b948146SAndy Fiddaman 		(void) strlcpy(sc->vsc_linkname, value, MAXLINKNAMELEN);
381b22a70abSPatrick Mooney 	}
382b22a70abSPatrick Mooney 
383b22a70abSPatrick Mooney 	DPRINTF(("viona=%p dev=%s vqsize=%x feature_mask=%x\n", sc,
384b22a70abSPatrick Mooney 	    sc->vsc_linkname, sc->vsc_vq_size, sc->vsc_feature_mask));
385b22a70abSPatrick Mooney 	return (err);
386b22a70abSPatrick Mooney }
387b22a70abSPatrick Mooney 
388b22a70abSPatrick Mooney static int
3892b948146SAndy Fiddaman pci_viona_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
390bf21cd93STycho Nightingale {
391bf21cd93STycho Nightingale 	dladm_handle_t		handle;
392bf21cd93STycho Nightingale 	dladm_status_t		status;
393bf21cd93STycho Nightingale 	dladm_vnic_attr_t	attr;
394bf21cd93STycho Nightingale 	char			errmsg[DLADM_STRSIZE];
395*39eba7d4SAndy Fiddaman 	char			tname[MAXCOMLEN + 1];
396b22a70abSPatrick Mooney 	int error, i;
397bf21cd93STycho Nightingale 	struct pci_viona_softc *sc;
398b22a70abSPatrick Mooney 	uint64_t ioport;
3992b948146SAndy Fiddaman 	const char *vnic;
400*39eba7d4SAndy 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 
455*39eba7d4SAndy Fiddaman 	error = pthread_create(&tid, NULL, pci_viona_poll_thread, sc);
456bf21cd93STycho Nightingale 	assert(error == 0);
457*39eba7d4SAndy Fiddaman 	snprintf(tname, sizeof (tname), "vionapoll:%s", vnic);
458*39eba7d4SAndy 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 
485b22a70abSPatrick Mooney 	/* Install ioport hook for virtqueue notification */
4862b948146SAndy Fiddaman 	ioport = pi->pi_bar[0].addr + VIRTIO_PCI_QUEUE_NOTIFY;
487b22a70abSPatrick Mooney 	error = ioctl(sc->vsc_vnafd, VNA_IOC_SET_NOTIFY_IOP, ioport);
488b22a70abSPatrick Mooney 	if (error != 0) {
489b22a70abSPatrick Mooney 		WPRINTF(("could not install ioport hook at %x\n", ioport));
490b22a70abSPatrick Mooney 		free(sc);
491b22a70abSPatrick Mooney 		return (1);
492bf21cd93STycho Nightingale 	}
493bf21cd93STycho Nightingale 
494bf21cd93STycho Nightingale 	/*
495b22a70abSPatrick Mooney 	 * Need a legacy interrupt for virtio compliance, even though MSI-X
496b22a70abSPatrick Mooney 	 * operation is _strongly_ suggested for adequate performance.
497bf21cd93STycho Nightingale 	 */
498b22a70abSPatrick Mooney 	pci_lintr_request(pi);
499b22a70abSPatrick Mooney 
500b22a70abSPatrick Mooney 	return (0);
501b22a70abSPatrick Mooney }
502bf21cd93STycho Nightingale 
503bf21cd93STycho Nightingale static uint64_t
504bf21cd93STycho Nightingale viona_adjust_offset(struct pci_devinst *pi, uint64_t offset)
505bf21cd93STycho Nightingale {
506bf21cd93STycho Nightingale 	/*
507bf21cd93STycho Nightingale 	 * Device specific offsets used by guest would change based on
508bf21cd93STycho Nightingale 	 * whether MSI-X capability is enabled or not
509bf21cd93STycho Nightingale 	 */
510bf21cd93STycho Nightingale 	if (!pci_msix_enabled(pi)) {
5112b948146SAndy Fiddaman 		if (offset >= VIRTIO_PCI_CONFIG_OFF(0)) {
5122b948146SAndy Fiddaman 			return (offset + (VIRTIO_PCI_CONFIG_OFF(1) -
5132b948146SAndy Fiddaman 			    VIRTIO_PCI_CONFIG_OFF(0)));
5142b948146SAndy Fiddaman 		}
515bf21cd93STycho Nightingale 	}
516bf21cd93STycho Nightingale 
517bf21cd93STycho Nightingale 	return (offset);
518bf21cd93STycho Nightingale }
519bf21cd93STycho Nightingale 
520bf21cd93STycho Nightingale static void
521b22a70abSPatrick Mooney pci_viona_ring_set_msix(struct pci_devinst *pi, uint_t ring)
522b22a70abSPatrick Mooney {
523b22a70abSPatrick Mooney 	struct pci_viona_softc *sc = pi->pi_arg;
524b22a70abSPatrick Mooney 	struct msix_table_entry mte;
525b22a70abSPatrick Mooney 	uint16_t tab_index;
526b22a70abSPatrick Mooney 	vioc_ring_msi_t vrm;
527b22a70abSPatrick Mooney 	int res;
528b22a70abSPatrick Mooney 
529b22a70abSPatrick Mooney 	assert(ring <= VIONA_VQ_TX);
530b22a70abSPatrick Mooney 
531b22a70abSPatrick Mooney 	vrm.rm_index = ring;
532b22a70abSPatrick Mooney 	vrm.rm_addr = 0;
533b22a70abSPatrick Mooney 	vrm.rm_msg = 0;
534b22a70abSPatrick Mooney 	tab_index = sc->vsc_msix_table_idx[ring];
535b22a70abSPatrick Mooney 
536b22a70abSPatrick Mooney 	if (tab_index != VIRTIO_MSI_NO_VECTOR && sc->vsc_msix_active) {
537b22a70abSPatrick Mooney 		mte = pi->pi_msix.table[tab_index];
538b22a70abSPatrick Mooney 		if ((mte.vector_control & PCIM_MSIX_VCTRL_MASK) == 0) {
539b22a70abSPatrick Mooney 			vrm.rm_addr = mte.addr;
540b22a70abSPatrick Mooney 			vrm.rm_msg = mte.msg_data;
541b22a70abSPatrick Mooney 		}
542b22a70abSPatrick Mooney 	}
543b22a70abSPatrick Mooney 
544b22a70abSPatrick Mooney 	res = ioctl(sc->vsc_vnafd, VNA_IOC_RING_SET_MSI, &vrm);
545b22a70abSPatrick Mooney 	if (res != 0) {
546b22a70abSPatrick Mooney 		WPRINTF(("ioctl viona set_msi %d failed %d\n", ring, errno));
547b22a70abSPatrick Mooney 	}
548b22a70abSPatrick Mooney }
549b22a70abSPatrick Mooney 
550b22a70abSPatrick Mooney static void
551b22a70abSPatrick Mooney pci_viona_lintrupdate(struct pci_devinst *pi)
552b22a70abSPatrick Mooney {
553b22a70abSPatrick Mooney 	struct pci_viona_softc *sc = pi->pi_arg;
554b22a70abSPatrick Mooney 	boolean_t msix_on = B_FALSE;
555b22a70abSPatrick Mooney 
556b22a70abSPatrick Mooney 	pthread_mutex_lock(&sc->vsc_mtx);
557b22a70abSPatrick Mooney 	msix_on = pci_msix_enabled(pi) && (pi->pi_msix.function_mask == 0);
558b22a70abSPatrick Mooney 	if ((sc->vsc_msix_active && !msix_on) ||
559b22a70abSPatrick Mooney 	    (msix_on && !sc->vsc_msix_active)) {
560b22a70abSPatrick Mooney 		uint_t i;
561b22a70abSPatrick Mooney 
562b22a70abSPatrick Mooney 		sc->vsc_msix_active = msix_on;
563b22a70abSPatrick Mooney 		/* Update in-kernel ring configs */
564b22a70abSPatrick Mooney 		for (i = 0; i <= VIONA_VQ_TX; i++) {
565b22a70abSPatrick Mooney 			pci_viona_ring_set_msix(pi, i);
566b22a70abSPatrick Mooney 		}
567b22a70abSPatrick Mooney 	}
568b22a70abSPatrick Mooney 	pthread_mutex_unlock(&sc->vsc_mtx);
569b22a70abSPatrick Mooney }
570b22a70abSPatrick Mooney 
571b22a70abSPatrick Mooney static void
572b22a70abSPatrick Mooney pci_viona_msix_update(struct pci_devinst *pi, uint64_t offset)
573b22a70abSPatrick Mooney {
574b22a70abSPatrick Mooney 	struct pci_viona_softc *sc = pi->pi_arg;
575b22a70abSPatrick Mooney 	uint_t tab_index, i;
576b22a70abSPatrick Mooney 
577b22a70abSPatrick Mooney 	pthread_mutex_lock(&sc->vsc_mtx);
578b22a70abSPatrick Mooney 	if (!sc->vsc_msix_active) {
579b22a70abSPatrick Mooney 		pthread_mutex_unlock(&sc->vsc_mtx);
580b22a70abSPatrick Mooney 		return;
581b22a70abSPatrick Mooney 	}
582b22a70abSPatrick Mooney 
583b22a70abSPatrick Mooney 	/*
584b22a70abSPatrick Mooney 	 * Rather than update every possible MSI-X vector, cheat and use the
585b22a70abSPatrick Mooney 	 * offset to calculate the entry within the table.  Since this should
586b22a70abSPatrick Mooney 	 * only be called when a write to the table succeeds, the index should
587b22a70abSPatrick Mooney 	 * be valid.
588b22a70abSPatrick Mooney 	 */
589b22a70abSPatrick Mooney 	tab_index = offset / MSIX_TABLE_ENTRY_SIZE;
590b22a70abSPatrick Mooney 
591b22a70abSPatrick Mooney 	for (i = 0; i <= VIONA_VQ_TX; i++) {
592b22a70abSPatrick Mooney 		if (sc->vsc_msix_table_idx[i] != tab_index) {
593b22a70abSPatrick Mooney 			continue;
594b22a70abSPatrick Mooney 		}
595b22a70abSPatrick Mooney 		pci_viona_ring_set_msix(pi, i);
596b22a70abSPatrick Mooney 	}
597b22a70abSPatrick Mooney 
598b22a70abSPatrick Mooney 	pthread_mutex_unlock(&sc->vsc_mtx);
599b22a70abSPatrick Mooney }
600b22a70abSPatrick Mooney 
601b22a70abSPatrick Mooney static void
602b22a70abSPatrick Mooney pci_viona_qnotify(struct pci_viona_softc *sc, int ring)
603b22a70abSPatrick Mooney {
604b22a70abSPatrick Mooney 	int error;
605b22a70abSPatrick Mooney 
606b22a70abSPatrick Mooney 	switch (ring) {
607b22a70abSPatrick Mooney 	case VIONA_TXQ:
608b22a70abSPatrick Mooney 	case VIONA_RXQ:
609b22a70abSPatrick Mooney 		error = ioctl(sc->vsc_vnafd, VNA_IOC_RING_KICK, ring);
610b22a70abSPatrick Mooney 		if (error != 0) {
611b22a70abSPatrick Mooney 			WPRINTF(("ioctl viona ring %d kick failed %d\n",
612b22a70abSPatrick Mooney 			    ring, errno));
613b22a70abSPatrick Mooney 		}
614b22a70abSPatrick Mooney 		break;
615b22a70abSPatrick Mooney 	case VIONA_CTLQ:
616b22a70abSPatrick Mooney 		DPRINTF(("viona: control qnotify!\n"));
617b22a70abSPatrick Mooney 		break;
618b22a70abSPatrick Mooney 	default:
619b22a70abSPatrick Mooney 		break;
620b22a70abSPatrick Mooney 	}
621b22a70abSPatrick Mooney }
622b22a70abSPatrick Mooney 
623b22a70abSPatrick Mooney static void
624bf21cd93STycho Nightingale pci_viona_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
625bf21cd93STycho Nightingale     int baridx, uint64_t offset, int size, uint64_t value)
626bf21cd93STycho Nightingale {
627bf21cd93STycho Nightingale 	struct pci_viona_softc *sc = pi->pi_arg;
628bf21cd93STycho Nightingale 	void *ptr;
629bf21cd93STycho Nightingale 	int err = 0;
630bf21cd93STycho Nightingale 
631bf21cd93STycho Nightingale 	if (baridx == pci_msix_table_bar(pi) ||
632bf21cd93STycho Nightingale 	    baridx == pci_msix_pba_bar(pi)) {
633b22a70abSPatrick Mooney 		if (pci_emul_msix_twrite(pi, offset, size, value) == 0) {
634b22a70abSPatrick Mooney 			pci_viona_msix_update(pi, offset);
635b22a70abSPatrick Mooney 		}
636bf21cd93STycho Nightingale 		return;
637bf21cd93STycho Nightingale 	}
638bf21cd93STycho Nightingale 
639bf21cd93STycho Nightingale 	assert(baridx == 0);
640bf21cd93STycho Nightingale 
641bf21cd93STycho Nightingale 	if (offset + size > pci_viona_iosize(pi)) {
642bf21cd93STycho Nightingale 		DPRINTF(("viona_write: 2big, offset %ld size %d\n",
643bf21cd93STycho Nightingale 		    offset, size));
644bf21cd93STycho Nightingale 		return;
645bf21cd93STycho Nightingale 	}
646bf21cd93STycho Nightingale 
647bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->vsc_mtx);
648bf21cd93STycho Nightingale 
649bf21cd93STycho Nightingale 	offset = viona_adjust_offset(pi, offset);
650bf21cd93STycho Nightingale 
651bf21cd93STycho Nightingale 	switch (offset) {
6522b948146SAndy Fiddaman 	case VIRTIO_PCI_GUEST_FEATURES:
653bf21cd93STycho Nightingale 		assert(size == 4);
654b22a70abSPatrick Mooney 		value &= ~(sc->vsc_feature_mask);
655bf21cd93STycho Nightingale 		err = ioctl(sc->vsc_vnafd, VNA_IOC_SET_FEATURES, &value);
656b22a70abSPatrick Mooney 		if (err != 0) {
657bf21cd93STycho Nightingale 			WPRINTF(("ioctl feature negotiation returned"
658b22a70abSPatrick Mooney 			    " err = %d\n", errno));
659b22a70abSPatrick Mooney 		} else {
660b22a70abSPatrick Mooney 			sc->vsc_features = value;
661b22a70abSPatrick Mooney 		}
662bf21cd93STycho Nightingale 		break;
6632b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_PFN:
664bf21cd93STycho Nightingale 		assert(size == 4);
665bf21cd93STycho Nightingale 		pci_viona_ring_init(sc, value);
666bf21cd93STycho Nightingale 		break;
6672b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_SEL:
668bf21cd93STycho Nightingale 		assert(size == 2);
669bf21cd93STycho Nightingale 		assert(value < VIONA_MAXQ);
670bf21cd93STycho Nightingale 		sc->vsc_curq = value;
671bf21cd93STycho Nightingale 		break;
6722b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_NOTIFY:
673bf21cd93STycho Nightingale 		assert(size == 2);
674bf21cd93STycho Nightingale 		assert(value < VIONA_MAXQ);
675b22a70abSPatrick Mooney 		pci_viona_qnotify(sc, value);
676bf21cd93STycho Nightingale 		break;
6772b948146SAndy Fiddaman 	case VIRTIO_PCI_STATUS:
678bf21cd93STycho Nightingale 		assert(size == 1);
679bf21cd93STycho Nightingale 		pci_viona_update_status(sc, value);
680bf21cd93STycho Nightingale 		break;
6812b948146SAndy Fiddaman 	case VIRTIO_MSI_CONFIG_VECTOR:
682bf21cd93STycho Nightingale 		assert(size == 2);
683bf21cd93STycho Nightingale 		sc->vsc_msix_table_idx[VIONA_CTLQ] = value;
684bf21cd93STycho Nightingale 		break;
6852b948146SAndy Fiddaman 	case VIRTIO_MSI_QUEUE_VECTOR:
686bf21cd93STycho Nightingale 		assert(size == 2);
687bf21cd93STycho Nightingale 		assert(sc->vsc_curq != VIONA_CTLQ);
688bf21cd93STycho Nightingale 		sc->vsc_msix_table_idx[sc->vsc_curq] = value;
689b22a70abSPatrick Mooney 		pci_viona_ring_set_msix(pi, sc->vsc_curq);
690bf21cd93STycho Nightingale 		break;
691bf21cd93STycho Nightingale 	case VIONA_R_CFG0:
692bf21cd93STycho Nightingale 	case VIONA_R_CFG1:
693bf21cd93STycho Nightingale 	case VIONA_R_CFG2:
694bf21cd93STycho Nightingale 	case VIONA_R_CFG3:
695bf21cd93STycho Nightingale 	case VIONA_R_CFG4:
696bf21cd93STycho Nightingale 	case VIONA_R_CFG5:
697bf21cd93STycho Nightingale 		assert((size + offset) <= (VIONA_R_CFG5 + 1));
698bf21cd93STycho Nightingale 		ptr = &sc->vsc_macaddr[offset - VIONA_R_CFG0];
699bf21cd93STycho Nightingale 		/*
700bf21cd93STycho Nightingale 		 * The driver is allowed to change the MAC address
701bf21cd93STycho Nightingale 		 */
702bf21cd93STycho Nightingale 		sc->vsc_macaddr[offset - VIONA_R_CFG0] = value;
703bf21cd93STycho Nightingale 		if (size == 1) {
704bf21cd93STycho Nightingale 			*(uint8_t *)ptr = value;
705bf21cd93STycho Nightingale 		} else if (size == 2) {
706bf21cd93STycho Nightingale 			*(uint16_t *)ptr = value;
707bf21cd93STycho Nightingale 		} else {
708bf21cd93STycho Nightingale 			*(uint32_t *)ptr = value;
709bf21cd93STycho Nightingale 		}
710bf21cd93STycho Nightingale 		break;
7112b948146SAndy Fiddaman 	case VIRTIO_PCI_HOST_FEATURES:
7122b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_NUM:
7132b948146SAndy Fiddaman 	case VIRTIO_PCI_ISR:
714bf21cd93STycho Nightingale 	case VIONA_R_CFG6:
715bf21cd93STycho Nightingale 	case VIONA_R_CFG7:
716bf21cd93STycho Nightingale 		DPRINTF(("viona: write to readonly reg %ld\n\r", offset));
717bf21cd93STycho Nightingale 		break;
718bf21cd93STycho Nightingale 	default:
719bf21cd93STycho Nightingale 		DPRINTF(("viona: unknown i/o write offset %ld\n\r", offset));
720bf21cd93STycho Nightingale 		value = 0;
721bf21cd93STycho Nightingale 		break;
722bf21cd93STycho Nightingale 	}
723bf21cd93STycho Nightingale 
724bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->vsc_mtx);
725bf21cd93STycho Nightingale }
726bf21cd93STycho Nightingale 
727b22a70abSPatrick Mooney static uint64_t
728bf21cd93STycho Nightingale pci_viona_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
729bf21cd93STycho Nightingale     int baridx, uint64_t offset, int size)
730bf21cd93STycho Nightingale {
731bf21cd93STycho Nightingale 	struct pci_viona_softc *sc = pi->pi_arg;
732bf21cd93STycho Nightingale 	void *ptr;
733bf21cd93STycho Nightingale 	uint64_t value;
734bf21cd93STycho Nightingale 	int err = 0;
735bf21cd93STycho Nightingale 
736bf21cd93STycho Nightingale 	if (baridx == pci_msix_table_bar(pi) ||
737bf21cd93STycho Nightingale 	    baridx == pci_msix_pba_bar(pi)) {
738bf21cd93STycho Nightingale 		return (pci_emul_msix_tread(pi, offset, size));
739bf21cd93STycho Nightingale 	}
740bf21cd93STycho Nightingale 
741bf21cd93STycho Nightingale 	assert(baridx == 0);
742bf21cd93STycho Nightingale 
743bf21cd93STycho Nightingale 	if (offset + size > pci_viona_iosize(pi)) {
744bf21cd93STycho Nightingale 		DPRINTF(("viona_read: 2big, offset %ld size %d\n",
745bf21cd93STycho Nightingale 		    offset, size));
746bf21cd93STycho Nightingale 		return (0);
747bf21cd93STycho Nightingale 	}
748bf21cd93STycho Nightingale 
749bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->vsc_mtx);
750bf21cd93STycho Nightingale 
751bf21cd93STycho Nightingale 	offset = viona_adjust_offset(pi, offset);
752bf21cd93STycho Nightingale 
753bf21cd93STycho Nightingale 	switch (offset) {
7542b948146SAndy Fiddaman 	case VIRTIO_PCI_HOST_FEATURES:
755bf21cd93STycho Nightingale 		assert(size == 4);
756bf21cd93STycho Nightingale 		err = ioctl(sc->vsc_vnafd, VNA_IOC_GET_FEATURES, &value);
757b22a70abSPatrick Mooney 		if (err != 0) {
758bf21cd93STycho Nightingale 			WPRINTF(("ioctl get host features returned"
759b22a70abSPatrick Mooney 			    " err = %d\n", errno));
760b22a70abSPatrick Mooney 		}
761b22a70abSPatrick Mooney 		value &= ~sc->vsc_feature_mask;
762bf21cd93STycho Nightingale 		break;
7632b948146SAndy Fiddaman 	case VIRTIO_PCI_GUEST_FEATURES:
764bf21cd93STycho Nightingale 		assert(size == 4);
765bf21cd93STycho Nightingale 		value = sc->vsc_features; /* XXX never read ? */
766bf21cd93STycho Nightingale 		break;
7672b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_PFN:
768bf21cd93STycho Nightingale 		assert(size == 4);
769bf21cd93STycho Nightingale 		value = sc->vsc_pfn[sc->vsc_curq] >> VRING_PFN;
770bf21cd93STycho Nightingale 		break;
7712b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_NUM:
772bf21cd93STycho Nightingale 		assert(size == 2);
773b22a70abSPatrick Mooney 		value = pci_viona_qsize(sc, sc->vsc_curq);
774bf21cd93STycho Nightingale 		break;
7752b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_SEL:
776bf21cd93STycho Nightingale 		assert(size == 2);
777bf21cd93STycho Nightingale 		value = sc->vsc_curq;  /* XXX never read ? */
778bf21cd93STycho Nightingale 		break;
7792b948146SAndy Fiddaman 	case VIRTIO_PCI_QUEUE_NOTIFY:
780bf21cd93STycho Nightingale 		assert(size == 2);
781bf21cd93STycho Nightingale 		value = sc->vsc_curq;  /* XXX never read ? */
782bf21cd93STycho Nightingale 		break;
7832b948146SAndy Fiddaman 	case VIRTIO_PCI_STATUS:
784bf21cd93STycho Nightingale 		assert(size == 1);
785bf21cd93STycho Nightingale 		value = sc->vsc_status;
786bf21cd93STycho Nightingale 		break;
7872b948146SAndy Fiddaman 	case VIRTIO_PCI_ISR:
788bf21cd93STycho Nightingale 		assert(size == 1);
789bf21cd93STycho Nightingale 		value = sc->vsc_isr;
790bf21cd93STycho Nightingale 		sc->vsc_isr = 0;	/* a read clears this flag */
791b22a70abSPatrick Mooney 		if (value != 0) {
792b22a70abSPatrick Mooney 			pci_lintr_deassert(pi);
793b22a70abSPatrick Mooney 		}
794bf21cd93STycho Nightingale 		break;
7952b948146SAndy Fiddaman 	case VIRTIO_MSI_CONFIG_VECTOR:
796bf21cd93STycho Nightingale 		assert(size == 2);
797bf21cd93STycho Nightingale 		value = sc->vsc_msix_table_idx[VIONA_CTLQ];
798bf21cd93STycho Nightingale 		break;
7992b948146SAndy Fiddaman 	case VIRTIO_MSI_QUEUE_VECTOR:
800bf21cd93STycho Nightingale 		assert(size == 2);
801bf21cd93STycho Nightingale 		assert(sc->vsc_curq != VIONA_CTLQ);
802bf21cd93STycho Nightingale 		value = sc->vsc_msix_table_idx[sc->vsc_curq];
803bf21cd93STycho Nightingale 		break;
804bf21cd93STycho Nightingale 	case VIONA_R_CFG0:
805bf21cd93STycho Nightingale 	case VIONA_R_CFG1:
806bf21cd93STycho Nightingale 	case VIONA_R_CFG2:
807bf21cd93STycho Nightingale 	case VIONA_R_CFG3:
808bf21cd93STycho Nightingale 	case VIONA_R_CFG4:
809bf21cd93STycho Nightingale 	case VIONA_R_CFG5:
810bf21cd93STycho Nightingale 		assert((size + offset) <= (VIONA_R_CFG5 + 1));
811bf21cd93STycho Nightingale 		ptr = &sc->vsc_macaddr[offset - VIONA_R_CFG0];
812bf21cd93STycho Nightingale 		if (size == 1) {
813bf21cd93STycho Nightingale 			value = *(uint8_t *)ptr;
814bf21cd93STycho Nightingale 		} else if (size == 2) {
815bf21cd93STycho Nightingale 			value = *(uint16_t *)ptr;
816bf21cd93STycho Nightingale 		} else {
817bf21cd93STycho Nightingale 			value = *(uint32_t *)ptr;
818bf21cd93STycho Nightingale 		}
819bf21cd93STycho Nightingale 		break;
820bf21cd93STycho Nightingale 	case VIONA_R_CFG6:
821bf21cd93STycho Nightingale 		assert(size != 4);
822bf21cd93STycho Nightingale 		value = 0x01;	/* XXX link always up */
823bf21cd93STycho Nightingale 		break;
824bf21cd93STycho Nightingale 	case VIONA_R_CFG7:
825bf21cd93STycho Nightingale 		assert(size == 1);
826bf21cd93STycho Nightingale 		value = 0;	/* XXX link status in LSB */
827bf21cd93STycho Nightingale 		break;
828bf21cd93STycho Nightingale 	default:
829bf21cd93STycho Nightingale 		DPRINTF(("viona: unknown i/o read offset %ld\n\r", offset));
830bf21cd93STycho Nightingale 		value = 0;
831bf21cd93STycho Nightingale 		break;
832bf21cd93STycho Nightingale 	}
833bf21cd93STycho Nightingale 
834bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->vsc_mtx);
835bf21cd93STycho Nightingale 
836bf21cd93STycho Nightingale 	return (value);
837bf21cd93STycho Nightingale }
838bf21cd93STycho Nightingale 
839bf21cd93STycho Nightingale struct pci_devemu pci_de_viona = {
840bf21cd93STycho Nightingale 	.pe_emu =	"virtio-net-viona",
841bf21cd93STycho Nightingale 	.pe_init =	pci_viona_init,
8422b948146SAndy Fiddaman 	.pe_legacy_config = pci_viona_legacy_config,
843bf21cd93STycho Nightingale 	.pe_barwrite =	pci_viona_write,
844b22a70abSPatrick Mooney 	.pe_barread =	pci_viona_read,
845b22a70abSPatrick Mooney 	.pe_lintrupdate = pci_viona_lintrupdate
846bf21cd93STycho Nightingale };
847bf21cd93STycho Nightingale PCI_EMUL_SET(pci_de_viona);
848