1b22a70abSPatrick Mooney /*
2b22a70abSPatrick Mooney  * Copyright (c) 2013  Chris Torek <torek @ torek net>
3b22a70abSPatrick Mooney  * All rights reserved.
4b22a70abSPatrick Mooney  *
5b22a70abSPatrick Mooney  * Redistribution and use in source and binary forms, with or without
6b22a70abSPatrick Mooney  * modification, are permitted provided that the following conditions
7b22a70abSPatrick Mooney  * are met:
8b22a70abSPatrick Mooney  * 1. Redistributions of source code must retain the above copyright
9b22a70abSPatrick Mooney  *    notice, this list of conditions and the following disclaimer.
10b22a70abSPatrick Mooney  * 2. Redistributions in binary form must reproduce the above copyright
11b22a70abSPatrick Mooney  *    notice, this list of conditions and the following disclaimer in the
12b22a70abSPatrick Mooney  *    documentation and/or other materials provided with the distribution.
13b22a70abSPatrick Mooney  *
14b22a70abSPatrick Mooney  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15b22a70abSPatrick Mooney  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16b22a70abSPatrick Mooney  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17b22a70abSPatrick Mooney  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18b22a70abSPatrick Mooney  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19b22a70abSPatrick Mooney  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20b22a70abSPatrick Mooney  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21b22a70abSPatrick Mooney  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22b22a70abSPatrick Mooney  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23b22a70abSPatrick Mooney  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24b22a70abSPatrick Mooney  * SUCH DAMAGE.
25b22a70abSPatrick Mooney  */
26b22a70abSPatrick Mooney /*
27b22a70abSPatrick Mooney  * This file and its contents are supplied under the terms of the
28b22a70abSPatrick Mooney  * Common Development and Distribution License ("CDDL"), version 1.0.
29b22a70abSPatrick Mooney  * You may only use this file in accordance with the terms of version
30b22a70abSPatrick Mooney  * 1.0 of the CDDL.
31b22a70abSPatrick Mooney  *
32b22a70abSPatrick Mooney  * A full copy of the text of the CDDL should have accompanied this
33b22a70abSPatrick Mooney  * source.  A copy of the CDDL is also available via the Internet at
34b22a70abSPatrick Mooney  * http://www.illumos.org/license/CDDL.
35b22a70abSPatrick Mooney  *
36b22a70abSPatrick Mooney  * Copyright 2015 Pluribus Networks Inc.
37b22a70abSPatrick Mooney  * Copyright 2019 Joyent, Inc.
38*d4221574SAndy Fiddaman  * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
391165c309SLuqman Aden  * Copyright 2023 Oxide Computer Company
40b22a70abSPatrick Mooney  */
41b22a70abSPatrick Mooney 
42b22a70abSPatrick Mooney /*
43b22a70abSPatrick Mooney  * viona - VirtIO-Net, Accelerated
44b22a70abSPatrick Mooney  *
45b22a70abSPatrick Mooney  * The purpose of viona is to provide high performance virtio-net devices to
46b22a70abSPatrick Mooney  * bhyve guests.  It does so by sitting directly atop MAC, skipping all of the
47b22a70abSPatrick Mooney  * DLS/DLD stack.
48b22a70abSPatrick Mooney  *
49b22a70abSPatrick Mooney  * --------------------
50b22a70abSPatrick Mooney  * General Architecture
51b22a70abSPatrick Mooney  * --------------------
52b22a70abSPatrick Mooney  *
53b22a70abSPatrick Mooney  * A single viona instance is comprised of a "link" handle and two "rings".
54b22a70abSPatrick Mooney  * After opening the viona device, it must be associated with a MAC network
55b22a70abSPatrick Mooney  * interface and a bhyve (vmm) instance to form its link resource.  This is
56b22a70abSPatrick Mooney  * done with the VNA_IOC_CREATE ioctl, where the datalink ID and vmm fd are
57b22a70abSPatrick Mooney  * passed in to perform the initialization.  With the MAC client opened, and a
58b22a70abSPatrick Mooney  * driver handle to the vmm instance established, the device is ready to be
59b22a70abSPatrick Mooney  * configured by the guest.
60b22a70abSPatrick Mooney  *
61b22a70abSPatrick Mooney  * The userspace portion of bhyve, which interfaces with the PCI device
62b22a70abSPatrick Mooney  * emulation framework, is meant to stay out of the datapath if at all
63b22a70abSPatrick Mooney  * possible.  Configuration changes made via PCI are mapped to actions which
64b22a70abSPatrick Mooney  * will steer the operation of the in-kernel logic.
65b22a70abSPatrick Mooney  *
66b22a70abSPatrick Mooney  *
67b22a70abSPatrick Mooney  * -----------
68b22a70abSPatrick Mooney  * Ring Basics
69b22a70abSPatrick Mooney  * -----------
70b22a70abSPatrick Mooney  *
71b22a70abSPatrick Mooney  * Each viona link has two viona_vring_t entities, RX and TX, for handling data
72b22a70abSPatrick Mooney  * transfers to and from the guest.  They represent an interface to the
73*d4221574SAndy Fiddaman  * standard virtio ring structures.  When initialized and active, each ring is
74b22a70abSPatrick Mooney  * backed by a kernel worker thread (parented to the bhyve process for the
75b22a70abSPatrick Mooney  * instance) which handles ring events.  The RX worker has the simple task of
76b22a70abSPatrick Mooney  * watching for ring shutdown conditions.  The TX worker does that in addition
77b22a70abSPatrick Mooney  * to processing all requests to transmit data.  Data destined for the guest is
78b22a70abSPatrick Mooney  * delivered directly by MAC to viona_rx() when the ring is active.
79b22a70abSPatrick Mooney  *
80b22a70abSPatrick Mooney  *
81b22a70abSPatrick Mooney  * -----------
82b22a70abSPatrick Mooney  * Ring States
83b22a70abSPatrick Mooney  * -----------
84b22a70abSPatrick Mooney  *
85b22a70abSPatrick Mooney  * The viona_vring_t instances follow a simple path through the possible state
86b22a70abSPatrick Mooney  * values represented in virtio_vring_t`vr_state:
87b22a70abSPatrick Mooney  *
88b22a70abSPatrick Mooney  *        +<--------------------------------------------+
89b22a70abSPatrick Mooney  *        |						|
90b22a70abSPatrick Mooney  *        V						^
91b22a70abSPatrick Mooney  *  +-----------+	This is the initial state when a link is created or
92b22a70abSPatrick Mooney  *  | VRS_RESET |	when the ring has been explicitly reset.
93b22a70abSPatrick Mooney  *  +-----------+
94b22a70abSPatrick Mooney  *        |						^
95b22a70abSPatrick Mooney  *        |---* ioctl(VNA_IOC_RING_INIT) issued		|
96b22a70abSPatrick Mooney  *        |						|
97b22a70abSPatrick Mooney  *        |						^
98b22a70abSPatrick Mooney  *        V
99b22a70abSPatrick Mooney  *  +-----------+	The ring parameters (size, guest physical addresses)
100b22a70abSPatrick Mooney  *  | VRS_SETUP |	have been set and start-up of the ring worker thread
101b22a70abSPatrick Mooney  *  +-----------+	has begun.
102b22a70abSPatrick Mooney  *        |						^
103b22a70abSPatrick Mooney  *        |						|
104b22a70abSPatrick Mooney  *        |---* ring worker thread begins execution	|
105b22a70abSPatrick Mooney  *        |						|
106b22a70abSPatrick Mooney  *        +-------------------------------------------->+
107b22a70abSPatrick Mooney  *        |	      |					^
108b22a70abSPatrick Mooney  *        |	      |
109b22a70abSPatrick Mooney  *        |	      *	If ring shutdown is requested (by ioctl or impending
110b22a70abSPatrick Mooney  *        |		bhyve process death) while the worker thread is
111b22a70abSPatrick Mooney  *        |		starting, the worker will transition the ring to
112b22a70abSPatrick Mooney  *        |		VRS_RESET and exit.
113b22a70abSPatrick Mooney  *        |						^
114b22a70abSPatrick Mooney  *        |						|
115a26f9c14SPatrick Mooney  *        |<-------------------------------------------<+
116a26f9c14SPatrick Mooney  *        |	      |					|
117a26f9c14SPatrick Mooney  *        |	      |					^
118a26f9c14SPatrick Mooney  *        |	      *	If ring is requested to pause (but not stop)from the
119a26f9c14SPatrick Mooney  *        |             VRS_RUN state, it will return to the VRS_INIT state.
120a26f9c14SPatrick Mooney  *        |
121a26f9c14SPatrick Mooney  *        |						^
122a26f9c14SPatrick Mooney  *        |						|
123b22a70abSPatrick Mooney  *        |						^
124b22a70abSPatrick Mooney  *        V
125b22a70abSPatrick Mooney  *  +-----------+	The worker thread associated with the ring has started
126b22a70abSPatrick Mooney  *  | VRS_INIT  |	executing.  It has allocated any extra resources needed
127b22a70abSPatrick Mooney  *  +-----------+	for the ring to operate.
128b22a70abSPatrick Mooney  *        |						^
129b22a70abSPatrick Mooney  *        |						|
130b22a70abSPatrick Mooney  *        +-------------------------------------------->+
131b22a70abSPatrick Mooney  *        |	      |					^
132b22a70abSPatrick Mooney  *        |	      |
133b22a70abSPatrick Mooney  *        |	      *	If ring shutdown is requested while the worker is
134b22a70abSPatrick Mooney  *        |		waiting in VRS_INIT, it will free any extra resources
135b22a70abSPatrick Mooney  *        |		and transition to VRS_RESET.
136b22a70abSPatrick Mooney  *        |						^
137b22a70abSPatrick Mooney  *        |						|
138b22a70abSPatrick Mooney  *        |--* ioctl(VNA_IOC_RING_KICK) issued		|
139b22a70abSPatrick Mooney  *        |						^
140b22a70abSPatrick Mooney  *        V
141b22a70abSPatrick Mooney  *  +-----------+	The worker thread associated with the ring is executing
142b22a70abSPatrick Mooney  *  | VRS_RUN   |	workload specific to that ring.
143b22a70abSPatrick Mooney  *  +-----------+
144b22a70abSPatrick Mooney  *        |						^
145b22a70abSPatrick Mooney  *        |---* ioctl(VNA_IOC_RING_RESET) issued	|
146b22a70abSPatrick Mooney  *        |	(or bhyve process begins exit)		^
147b22a70abSPatrick Mooney  *        |
148b22a70abSPatrick Mooney  *  +-----------+	The worker thread associated with the ring is in the
149b22a70abSPatrick Mooney  *  | VRS_STOP  |	process of exiting. All outstanding TX and RX
150b22a70abSPatrick Mooney  *  +-----------+	requests are allowed to complete, but new requests
151b22a70abSPatrick Mooney  *        |		must be ignored.
152b22a70abSPatrick Mooney  *        |						^
153b22a70abSPatrick Mooney  *        |						|
154b22a70abSPatrick Mooney  *        +-------------------------------------------->+
155b22a70abSPatrick Mooney  *
156b22a70abSPatrick Mooney  *
157b22a70abSPatrick Mooney  * While the worker thread is not running, changes to vr_state are only made by
158b22a70abSPatrick Mooney  * viona_ioc_ring_init() under vr_lock.  There, it initializes the ring, starts
159b22a70abSPatrick Mooney  * the worker, and sets the ring state to VRS_SETUP.  Once the worker thread
160b22a70abSPatrick Mooney  * has been started, only it may perform ring state transitions (still under
161b22a70abSPatrick Mooney  * the protection of vr_lock), when requested by outside consumers via
162b22a70abSPatrick Mooney  * vr_state_flags or when the containing bhyve process initiates an exit.
163b22a70abSPatrick Mooney  *
164b22a70abSPatrick Mooney  *
165b22a70abSPatrick Mooney  * ----------------------------
166b22a70abSPatrick Mooney  * Transmission mblk_t Handling
167b22a70abSPatrick Mooney  * ----------------------------
168b22a70abSPatrick Mooney  *
169b22a70abSPatrick Mooney  * For incoming frames destined for a bhyve guest, the data must first land in
170b22a70abSPatrick Mooney  * a host OS buffer from the physical NIC before it is copied into the awaiting
171b22a70abSPatrick Mooney  * guest buffer(s).  Outbound frames transmitted by the guest are not bound by
172b22a70abSPatrick Mooney  * this limitation and can avoid extra copying before the buffers are accessed
173b22a70abSPatrick Mooney  * directly by the NIC.  When a guest designates buffers to be transmitted,
174b22a70abSPatrick Mooney  * viona translates the guest-physical addresses contained in the ring
175427f9b9aSPatrick Mooney  * descriptors to host-virtual addresses via viona_hold_page().  That pointer is
176b22a70abSPatrick Mooney  * wrapped in an mblk_t using a preallocated viona_desb_t for the desballoc().
177b22a70abSPatrick Mooney  * Doing so increments vr_xfer_outstanding, preventing the ring from being
178b22a70abSPatrick Mooney  * reset (allowing the link to drop its vmm handle to the guest) until all
179b22a70abSPatrick Mooney  * transmit mblks referencing guest memory have been processed.  Allocation of
180b22a70abSPatrick Mooney  * the viona_desb_t entries is done during the VRS_INIT stage of the ring
181b22a70abSPatrick Mooney  * worker thread.  The ring size informs that allocation as the number of
182b22a70abSPatrick Mooney  * concurrent transmissions is limited by the number of descriptors in the
18326613631SDan Cross  * ring.  This minimizes allocation in the transmit hot-path by acquiring those
184b22a70abSPatrick Mooney  * fixed-size resources during initialization.
185b22a70abSPatrick Mooney  *
186b22a70abSPatrick Mooney  * This optimization depends on the underlying NIC driver freeing the mblks in
187b22a70abSPatrick Mooney  * a timely manner after they have been transmitted by the hardware.  Some
188b22a70abSPatrick Mooney  * drivers have been found to flush TX descriptors only when new transmissions
189b22a70abSPatrick Mooney  * are initiated.  This means that there is no upper bound to the time needed
190b22a70abSPatrick Mooney  * for an mblk to be flushed and can stall bhyve guests from shutting down
191b22a70abSPatrick Mooney  * since their memory must be free of viona TX references prior to clean-up.
192b22a70abSPatrick Mooney  *
193b22a70abSPatrick Mooney  * This expectation of deterministic mblk_t processing is likely the reason
194b22a70abSPatrick Mooney  * behind the notable exception to the zero-copy TX path: systems with 'bnxe'
195b22a70abSPatrick Mooney  * loaded will copy transmit data into fresh buffers rather than passing up
196b22a70abSPatrick Mooney  * zero-copy mblks.  It is a hold-over from the original viona sources provided
197b22a70abSPatrick Mooney  * by Pluribus and its continued necessity has not been confirmed.
198b22a70abSPatrick Mooney  *
199b22a70abSPatrick Mooney  *
200b22a70abSPatrick Mooney  * ----------------------------
201b22a70abSPatrick Mooney  * Ring Notification Fast-paths
202b22a70abSPatrick Mooney  * ----------------------------
203b22a70abSPatrick Mooney  *
204b22a70abSPatrick Mooney  * Device operation for viona requires that notifications flow to and from the
205b22a70abSPatrick Mooney  * guest to indicate certain ring conditions.  In order to minimize latency and
206b22a70abSPatrick Mooney  * processing overhead, the notification procedures are kept in-kernel whenever
207b22a70abSPatrick Mooney  * possible.
208b22a70abSPatrick Mooney  *
209b22a70abSPatrick Mooney  * Guest-to-host notifications, when new available descriptors have been placed
210b22a70abSPatrick Mooney  * in the ring, are posted via the 'queue notify' address in the virtio BAR.
211b22a70abSPatrick Mooney  * The vmm_drv_ioport_hook() interface was added to bhyve which allows viona to
212b22a70abSPatrick Mooney  * install a callback hook on an ioport address.  Guest exits for accesses to
213b22a70abSPatrick Mooney  * viona-hooked ioport addresses will result in direct calls to notify the
214b22a70abSPatrick Mooney  * appropriate ring worker without a trip to userland.
215b22a70abSPatrick Mooney  *
216b22a70abSPatrick Mooney  * Host-to-guest notifications in the form of interrupts enjoy similar
217b22a70abSPatrick Mooney  * acceleration.  Each viona ring can be configured to send MSI notifications
218b22a70abSPatrick Mooney  * to the guest as virtio conditions dictate.  This in-kernel interrupt
219b22a70abSPatrick Mooney  * configuration is kept synchronized through viona ioctls which are utilized
220b22a70abSPatrick Mooney  * during writes to the associated PCI config registers or MSI-X BAR.
221b22a70abSPatrick Mooney  *
222b22a70abSPatrick Mooney  * Guests which do not utilize MSI-X will result in viona falling back to the
223b22a70abSPatrick Mooney  * slow path for interrupts.  It will poll(2) the viona handle, receiving
224b22a70abSPatrick Mooney  * notification when ring events necessitate the assertion of an interrupt.
225b22a70abSPatrick Mooney  *
226b22a70abSPatrick Mooney  *
227b22a70abSPatrick Mooney  * ---------------
228b22a70abSPatrick Mooney  * Nethook Support
229b22a70abSPatrick Mooney  * ---------------
230b22a70abSPatrick Mooney  *
231b22a70abSPatrick Mooney  * Viona provides four nethook events that consumers (e.g. ipf) can hook into
232b22a70abSPatrick Mooney  * to intercept packets as they go up or down the stack.  Unfortunately,
233b22a70abSPatrick Mooney  * the nethook framework does not understand raw packets, so we can only
234b22a70abSPatrick Mooney  * generate events (in, out) for IPv4 and IPv6 packets.  At driver attach,
235b22a70abSPatrick Mooney  * we register callbacks with the neti (netinfo) module that will be invoked
236b22a70abSPatrick Mooney  * for each netstack already present, as well as for any additional netstack
237b22a70abSPatrick Mooney  * instances created as the system operates.  These callbacks will
238b22a70abSPatrick Mooney  * register/unregister the hooks with the nethook framework for each
239b22a70abSPatrick Mooney  * netstack instance.  This registration occurs prior to creating any
240b22a70abSPatrick Mooney  * viona instances for a given netstack, and the unregistration for a netstack
241b22a70abSPatrick Mooney  * instance occurs after all viona instances of the netstack instance have
242b22a70abSPatrick Mooney  * been deleted.
243b22a70abSPatrick Mooney  */
244b22a70abSPatrick Mooney 
245b22a70abSPatrick Mooney #include <sys/conf.h>
246b22a70abSPatrick Mooney #include <sys/file.h>
247b22a70abSPatrick Mooney #include <sys/stat.h>
248b22a70abSPatrick Mooney 
249b22a70abSPatrick Mooney #include <sys/dlpi.h>
2501165c309SLuqman Aden #include <sys/vlan.h>
251b22a70abSPatrick Mooney 
252b22a70abSPatrick Mooney #include "viona_impl.h"
253b22a70abSPatrick Mooney 
254b22a70abSPatrick Mooney 
255b22a70abSPatrick Mooney #define	VIONA_NAME		"Virtio Network Accelerator"
256b22a70abSPatrick Mooney #define	VIONA_CTL_MINOR		0
257b22a70abSPatrick Mooney #define	VIONA_CLI_NAME		"viona"		/* MAC client name */
258b22a70abSPatrick Mooney 
259b22a70abSPatrick Mooney 
260b22a70abSPatrick Mooney /*
261b22a70abSPatrick Mooney  * Host capabilities.
262b22a70abSPatrick Mooney  */
263b22a70abSPatrick Mooney #define	VIONA_S_HOSTCAPS	(	\
264b22a70abSPatrick Mooney 	VIRTIO_NET_F_GUEST_CSUM |	\
265b22a70abSPatrick Mooney 	VIRTIO_NET_F_MAC |		\
266b22a70abSPatrick Mooney 	VIRTIO_NET_F_GUEST_TSO4 |	\
267b22a70abSPatrick Mooney 	VIRTIO_NET_F_MRG_RXBUF |	\
268b22a70abSPatrick Mooney 	VIRTIO_NET_F_STATUS |		\
269b22a70abSPatrick Mooney 	VIRTIO_F_RING_NOTIFY_ON_EMPTY |	\
270b22a70abSPatrick Mooney 	VIRTIO_F_RING_INDIRECT_DESC)
271b22a70abSPatrick Mooney 
272b22a70abSPatrick Mooney /* MAC_CAPAB_HCKSUM specifics of interest */
273b22a70abSPatrick Mooney #define	VIONA_CAP_HCKSUM_INTEREST	\
274b22a70abSPatrick Mooney 	(HCKSUM_INET_PARTIAL |		\
275b22a70abSPatrick Mooney 	HCKSUM_INET_FULL_V4 |		\
276b22a70abSPatrick Mooney 	HCKSUM_INET_FULL_V6)
277b22a70abSPatrick Mooney 
278b22a70abSPatrick Mooney static void		*viona_state;
279b22a70abSPatrick Mooney static dev_info_t	*viona_dip;
280b22a70abSPatrick Mooney static id_space_t	*viona_minors;
281b22a70abSPatrick Mooney 
282b22a70abSPatrick Mooney 
283b22a70abSPatrick Mooney static int viona_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
284b22a70abSPatrick Mooney     void **result);
285b22a70abSPatrick Mooney static int viona_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
286b22a70abSPatrick Mooney static int viona_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
287b22a70abSPatrick Mooney static int viona_open(dev_t *devp, int flag, int otype, cred_t *credp);
288b22a70abSPatrick Mooney static int viona_close(dev_t dev, int flag, int otype, cred_t *credp);
289b22a70abSPatrick Mooney static int viona_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
290b22a70abSPatrick Mooney     cred_t *credp, int *rval);
291b22a70abSPatrick Mooney static int viona_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
292b22a70abSPatrick Mooney     struct pollhead **phpp);
293b22a70abSPatrick Mooney 
294b22a70abSPatrick Mooney static int viona_ioc_create(viona_soft_state_t *, void *, int, cred_t *);
295b22a70abSPatrick Mooney static int viona_ioc_delete(viona_soft_state_t *, boolean_t);
296b22a70abSPatrick Mooney 
2970e1453c3SPatrick Mooney static int viona_ioc_set_notify_ioport(viona_link_t *, uint16_t);
298*d4221574SAndy Fiddaman static int viona_ioc_set_promisc(viona_link_t *, viona_promisc_t);
299b22a70abSPatrick Mooney static int viona_ioc_ring_init(viona_link_t *, void *, int);
300a26f9c14SPatrick Mooney static int viona_ioc_ring_set_state(viona_link_t *, void *, int);
301a26f9c14SPatrick Mooney static int viona_ioc_ring_get_state(viona_link_t *, void *, int);
302b22a70abSPatrick Mooney static int viona_ioc_ring_reset(viona_link_t *, uint_t);
303b22a70abSPatrick Mooney static int viona_ioc_ring_kick(viona_link_t *, uint_t);
304a26f9c14SPatrick Mooney static int viona_ioc_ring_pause(viona_link_t *, uint_t);
305b22a70abSPatrick Mooney static int viona_ioc_ring_set_msi(viona_link_t *, void *, int);
306b22a70abSPatrick Mooney static int viona_ioc_ring_intr_clear(viona_link_t *, uint_t);
307b22a70abSPatrick Mooney static int viona_ioc_intr_poll(viona_link_t *, void *, int, int *);
308b22a70abSPatrick Mooney 
309b22a70abSPatrick Mooney static struct cb_ops viona_cb_ops = {
310b22a70abSPatrick Mooney 	viona_open,
311b22a70abSPatrick Mooney 	viona_close,
312b22a70abSPatrick Mooney 	nodev,
313b22a70abSPatrick Mooney 	nodev,
314b22a70abSPatrick Mooney 	nodev,
315b22a70abSPatrick Mooney 	nodev,
316b22a70abSPatrick Mooney 	nodev,
317b22a70abSPatrick Mooney 	viona_ioctl,
318b22a70abSPatrick Mooney 	nodev,
319b22a70abSPatrick Mooney 	nodev,
320b22a70abSPatrick Mooney 	nodev,
321b22a70abSPatrick Mooney 	viona_chpoll,
322b22a70abSPatrick Mooney 	ddi_prop_op,
323b22a70abSPatrick Mooney 	0,
324b22a70abSPatrick Mooney 	D_MP | D_NEW | D_HOTPLUG,
325b22a70abSPatrick Mooney 	CB_REV,
326b22a70abSPatrick Mooney 	nodev,
327b22a70abSPatrick Mooney 	nodev
328b22a70abSPatrick Mooney };
329b22a70abSPatrick Mooney 
330b22a70abSPatrick Mooney static struct dev_ops viona_ops = {
331b22a70abSPatrick Mooney 	DEVO_REV,
332b22a70abSPatrick Mooney 	0,
333b22a70abSPatrick Mooney 	viona_info,
334b22a70abSPatrick Mooney 	nulldev,
335b22a70abSPatrick Mooney 	nulldev,
336b22a70abSPatrick Mooney 	viona_attach,
337b22a70abSPatrick Mooney 	viona_detach,
338b22a70abSPatrick Mooney 	nodev,
339b22a70abSPatrick Mooney 	&viona_cb_ops,
340b22a70abSPatrick Mooney 	NULL,
341b22a70abSPatrick Mooney 	ddi_power,
342b22a70abSPatrick Mooney 	ddi_quiesce_not_needed
343b22a70abSPatrick Mooney };
344b22a70abSPatrick Mooney 
345b22a70abSPatrick Mooney static struct modldrv modldrv = {
346b22a70abSPatrick Mooney 	&mod_driverops,
347b22a70abSPatrick Mooney 	VIONA_NAME,
348b22a70abSPatrick Mooney 	&viona_ops,
349b22a70abSPatrick Mooney };
350b22a70abSPatrick Mooney 
351b22a70abSPatrick Mooney static struct modlinkage modlinkage = {
352b22a70abSPatrick Mooney 	MODREV_1, &modldrv, NULL
353b22a70abSPatrick Mooney };
354b22a70abSPatrick Mooney 
355b22a70abSPatrick Mooney int
_init(void)356b22a70abSPatrick Mooney _init(void)
357b22a70abSPatrick Mooney {
358b22a70abSPatrick Mooney 	int ret;
359b22a70abSPatrick Mooney 
360b22a70abSPatrick Mooney 	ret = ddi_soft_state_init(&viona_state, sizeof (viona_soft_state_t), 0);
361b22a70abSPatrick Mooney 	if (ret != 0) {
362b22a70abSPatrick Mooney 		return (ret);
363b22a70abSPatrick Mooney 	}
364b22a70abSPatrick Mooney 
365b22a70abSPatrick Mooney 	viona_minors = id_space_create("viona_minors",
366b22a70abSPatrick Mooney 	    VIONA_CTL_MINOR + 1, UINT16_MAX);
367b22a70abSPatrick Mooney 	viona_rx_init();
368b22a70abSPatrick Mooney 	mutex_init(&viona_force_copy_lock, NULL, MUTEX_DRIVER, NULL);
369b22a70abSPatrick Mooney 
370b22a70abSPatrick Mooney 	ret = mod_install(&modlinkage);
371b22a70abSPatrick Mooney 	if (ret != 0) {
372b22a70abSPatrick Mooney 		ddi_soft_state_fini(&viona_state);
373b22a70abSPatrick Mooney 		id_space_destroy(viona_minors);
374b22a70abSPatrick Mooney 		viona_rx_fini();
375b22a70abSPatrick Mooney 		mutex_destroy(&viona_force_copy_lock);
376b22a70abSPatrick Mooney 	}
377b22a70abSPatrick Mooney 
378b22a70abSPatrick Mooney 	return (ret);
379b22a70abSPatrick Mooney }
380b22a70abSPatrick Mooney 
381b22a70abSPatrick Mooney int
_fini(void)382b22a70abSPatrick Mooney _fini(void)
383b22a70abSPatrick Mooney {
384b22a70abSPatrick Mooney 	int ret;
385b22a70abSPatrick Mooney 
386b22a70abSPatrick Mooney 	ret = mod_remove(&modlinkage);
387b22a70abSPatrick Mooney 	if (ret != 0) {
388b22a70abSPatrick Mooney 		return (ret);
389b22a70abSPatrick Mooney 	}
390b22a70abSPatrick Mooney 
391b22a70abSPatrick Mooney 	ddi_soft_state_fini(&viona_state);
392b22a70abSPatrick Mooney 	id_space_destroy(viona_minors);
393b22a70abSPatrick Mooney 	viona_rx_fini();
394b22a70abSPatrick Mooney 	mutex_destroy(&viona_force_copy_lock);
395b22a70abSPatrick Mooney 
396b22a70abSPatrick Mooney 	return (ret);
397b22a70abSPatrick Mooney }
398b22a70abSPatrick Mooney 
399b22a70abSPatrick Mooney int
_info(struct modinfo * modinfop)400b22a70abSPatrick Mooney _info(struct modinfo *modinfop)
401b22a70abSPatrick Mooney {
402b22a70abSPatrick Mooney 	return (mod_info(&modlinkage, modinfop));
403b22a70abSPatrick Mooney }
404b22a70abSPatrick Mooney 
405b22a70abSPatrick Mooney /* ARGSUSED */
406b22a70abSPatrick Mooney static int
viona_info(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)407b22a70abSPatrick Mooney viona_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
408b22a70abSPatrick Mooney {
409b22a70abSPatrick Mooney 	int error;
410b22a70abSPatrick Mooney 
411b22a70abSPatrick Mooney 	switch (cmd) {
412b22a70abSPatrick Mooney 	case DDI_INFO_DEVT2DEVINFO:
413b22a70abSPatrick Mooney 		*result = (void *)viona_dip;
414b22a70abSPatrick Mooney 		error = DDI_SUCCESS;
415b22a70abSPatrick Mooney 		break;
416b22a70abSPatrick Mooney 	case DDI_INFO_DEVT2INSTANCE:
417b22a70abSPatrick Mooney 		*result = (void *)0;
418b22a70abSPatrick Mooney 		error = DDI_SUCCESS;
419b22a70abSPatrick Mooney 		break;
420b22a70abSPatrick Mooney 	default:
421b22a70abSPatrick Mooney 		error = DDI_FAILURE;
422b22a70abSPatrick Mooney 		break;
423b22a70abSPatrick Mooney 	}
424b22a70abSPatrick Mooney 	return (error);
425b22a70abSPatrick Mooney }
426b22a70abSPatrick Mooney 
427b22a70abSPatrick Mooney static int
viona_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)428b22a70abSPatrick Mooney viona_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
429b22a70abSPatrick Mooney {
430b22a70abSPatrick Mooney 	if (cmd != DDI_ATTACH) {
431b22a70abSPatrick Mooney 		return (DDI_FAILURE);
432b22a70abSPatrick Mooney 	}
433b22a70abSPatrick Mooney 
434b22a70abSPatrick Mooney 	if (ddi_create_minor_node(dip, "viona", S_IFCHR, VIONA_CTL_MINOR,
435b22a70abSPatrick Mooney 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
436b22a70abSPatrick Mooney 		return (DDI_FAILURE);
437b22a70abSPatrick Mooney 	}
438b22a70abSPatrick Mooney 
439b22a70abSPatrick Mooney 	viona_neti_attach();
440b22a70abSPatrick Mooney 
441b22a70abSPatrick Mooney 	viona_dip = dip;
442b22a70abSPatrick Mooney 	ddi_report_dev(viona_dip);
443b22a70abSPatrick Mooney 
444b22a70abSPatrick Mooney 	return (DDI_SUCCESS);
445b22a70abSPatrick Mooney }
446b22a70abSPatrick Mooney 
447b22a70abSPatrick Mooney static int
viona_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)448b22a70abSPatrick Mooney viona_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
449b22a70abSPatrick Mooney {
450b22a70abSPatrick Mooney 	dev_info_t *old_dip = viona_dip;
451b22a70abSPatrick Mooney 
452b22a70abSPatrick Mooney 	if (cmd != DDI_DETACH) {
453b22a70abSPatrick Mooney 		return (DDI_FAILURE);
454b22a70abSPatrick Mooney 	}
455b22a70abSPatrick Mooney 
456b22a70abSPatrick Mooney 	VERIFY(old_dip != NULL);
457b22a70abSPatrick Mooney 
458b22a70abSPatrick Mooney 	viona_neti_detach();
459b22a70abSPatrick Mooney 	viona_dip = NULL;
460b22a70abSPatrick Mooney 	ddi_remove_minor_node(old_dip, NULL);
461b22a70abSPatrick Mooney 
462b22a70abSPatrick Mooney 	return (DDI_SUCCESS);
463b22a70abSPatrick Mooney }
464b22a70abSPatrick Mooney 
465b22a70abSPatrick Mooney static int
viona_open(dev_t * devp,int flag,int otype,cred_t * credp)466b22a70abSPatrick Mooney viona_open(dev_t *devp, int flag, int otype, cred_t *credp)
467b22a70abSPatrick Mooney {
468b22a70abSPatrick Mooney 	int	minor;
469b22a70abSPatrick Mooney 	viona_soft_state_t *ss;
470b22a70abSPatrick Mooney 
471b22a70abSPatrick Mooney 	if (otype != OTYP_CHR) {
472b22a70abSPatrick Mooney 		return (EINVAL);
473b22a70abSPatrick Mooney 	}
474b22a70abSPatrick Mooney #if 0
475b22a70abSPatrick Mooney 	/*
476b22a70abSPatrick Mooney 	 * XXX-mg: drv_priv() is wrong, but I'm not sure what is right.
477b22a70abSPatrick Mooney 	 * Should the check be at open() or ioctl()?
478b22a70abSPatrick Mooney 	 */
479b22a70abSPatrick Mooney 	if (drv_priv(credp) != 0) {
480b22a70abSPatrick Mooney 		return (EPERM);
481b22a70abSPatrick Mooney 	}
482b22a70abSPatrick Mooney #endif
483b22a70abSPatrick Mooney 	if (getminor(*devp) != VIONA_CTL_MINOR) {
484b22a70abSPatrick Mooney 		return (ENXIO);
485b22a70abSPatrick Mooney 	}
486b22a70abSPatrick Mooney 
487b22a70abSPatrick Mooney 	minor = id_alloc_nosleep(viona_minors);
488b22a70abSPatrick Mooney 	if (minor == -1) {
489b22a70abSPatrick Mooney 		/* All minors are busy */
490b22a70abSPatrick Mooney 		return (EBUSY);
491b22a70abSPatrick Mooney 	}
492b22a70abSPatrick Mooney 	if (ddi_soft_state_zalloc(viona_state, minor) != DDI_SUCCESS) {
493b22a70abSPatrick Mooney 		id_free(viona_minors, minor);
494b22a70abSPatrick Mooney 		return (ENOMEM);
495b22a70abSPatrick Mooney 	}
496b22a70abSPatrick Mooney 
497b22a70abSPatrick Mooney 	ss = ddi_get_soft_state(viona_state, minor);
498b22a70abSPatrick Mooney 	mutex_init(&ss->ss_lock, NULL, MUTEX_DEFAULT, NULL);
499b22a70abSPatrick Mooney 	*devp = makedevice(getmajor(*devp), minor);
500b22a70abSPatrick Mooney 
501b22a70abSPatrick Mooney 	return (0);
502b22a70abSPatrick Mooney }
503b22a70abSPatrick Mooney 
504b22a70abSPatrick Mooney static int
viona_close(dev_t dev,int flag,int otype,cred_t * credp)505b22a70abSPatrick Mooney viona_close(dev_t dev, int flag, int otype, cred_t *credp)
506b22a70abSPatrick Mooney {
507b22a70abSPatrick Mooney 	int			minor;
508b22a70abSPatrick Mooney 	viona_soft_state_t	*ss;
509b22a70abSPatrick Mooney 
510b22a70abSPatrick Mooney 	if (otype != OTYP_CHR) {
511b22a70abSPatrick Mooney 		return (EINVAL);
512b22a70abSPatrick Mooney 	}
513b22a70abSPatrick Mooney 
514b22a70abSPatrick Mooney 	minor = getminor(dev);
515b22a70abSPatrick Mooney 
516b22a70abSPatrick Mooney 	ss = ddi_get_soft_state(viona_state, minor);
517b22a70abSPatrick Mooney 	if (ss == NULL) {
518b22a70abSPatrick Mooney 		return (ENXIO);
519b22a70abSPatrick Mooney 	}
520b22a70abSPatrick Mooney 
521b22a70abSPatrick Mooney 	VERIFY0(viona_ioc_delete(ss, B_TRUE));
522b22a70abSPatrick Mooney 	VERIFY(!list_link_active(&ss->ss_node));
523b22a70abSPatrick Mooney 	ddi_soft_state_free(viona_state, minor);
524b22a70abSPatrick Mooney 	id_free(viona_minors, minor);
525b22a70abSPatrick Mooney 
526b22a70abSPatrick Mooney 	return (0);
527b22a70abSPatrick Mooney }
528b22a70abSPatrick Mooney 
529b22a70abSPatrick Mooney static int
viona_ioctl(dev_t dev,int cmd,intptr_t data,int md,cred_t * cr,int * rv)530b22a70abSPatrick Mooney viona_ioctl(dev_t dev, int cmd, intptr_t data, int md, cred_t *cr, int *rv)
531b22a70abSPatrick Mooney {
532b22a70abSPatrick Mooney 	viona_soft_state_t *ss;
533b22a70abSPatrick Mooney 	void *dptr = (void *)data;
534b22a70abSPatrick Mooney 	int err = 0, val;
535b22a70abSPatrick Mooney 	viona_link_t *link;
536b22a70abSPatrick Mooney 
537b22a70abSPatrick Mooney 	ss = ddi_get_soft_state(viona_state, getminor(dev));
538b22a70abSPatrick Mooney 	if (ss == NULL) {
539b22a70abSPatrick Mooney 		return (ENXIO);
540b22a70abSPatrick Mooney 	}
541b22a70abSPatrick Mooney 
542b22a70abSPatrick Mooney 	switch (cmd) {
543b22a70abSPatrick Mooney 	case VNA_IOC_CREATE:
544b22a70abSPatrick Mooney 		return (viona_ioc_create(ss, dptr, md, cr));
545b22a70abSPatrick Mooney 	case VNA_IOC_DELETE:
546b22a70abSPatrick Mooney 		return (viona_ioc_delete(ss, B_FALSE));
547a26f9c14SPatrick Mooney 	case VNA_IOC_VERSION:
548a26f9c14SPatrick Mooney 		*rv = VIONA_CURRENT_INTERFACE_VERSION;
549a26f9c14SPatrick Mooney 		return (0);
550b22a70abSPatrick Mooney 	default:
551b22a70abSPatrick Mooney 		break;
552b22a70abSPatrick Mooney 	}
553b22a70abSPatrick Mooney 
554b22a70abSPatrick Mooney 	mutex_enter(&ss->ss_lock);
555b22a70abSPatrick Mooney 	if ((link = ss->ss_link) == NULL || link->l_destroyed ||
556b22a70abSPatrick Mooney 	    vmm_drv_release_reqd(link->l_vm_hold)) {
557b22a70abSPatrick Mooney 		mutex_exit(&ss->ss_lock);
558b22a70abSPatrick Mooney 		return (ENXIO);
559b22a70abSPatrick Mooney 	}
560b22a70abSPatrick Mooney 
561b22a70abSPatrick Mooney 	switch (cmd) {
562b22a70abSPatrick Mooney 	case VNA_IOC_GET_FEATURES:
563b22a70abSPatrick Mooney 		val = VIONA_S_HOSTCAPS | link->l_features_hw;
564b22a70abSPatrick Mooney 		if (ddi_copyout(&val, dptr, sizeof (val), md) != 0) {
565b22a70abSPatrick Mooney 			err = EFAULT;
566b22a70abSPatrick Mooney 		}
567b22a70abSPatrick Mooney 		break;
568b22a70abSPatrick Mooney 	case VNA_IOC_SET_FEATURES:
569b22a70abSPatrick Mooney 		if (ddi_copyin(dptr, &val, sizeof (val), md) != 0) {
570b22a70abSPatrick Mooney 			err = EFAULT;
571b22a70abSPatrick Mooney 			break;
572b22a70abSPatrick Mooney 		}
573b22a70abSPatrick Mooney 		val &= (VIONA_S_HOSTCAPS | link->l_features_hw);
574b22a70abSPatrick Mooney 
575b22a70abSPatrick Mooney 		if ((val & VIRTIO_NET_F_CSUM) == 0)
576b22a70abSPatrick Mooney 			val &= ~VIRTIO_NET_F_HOST_TSO4;
577b22a70abSPatrick Mooney 
578b22a70abSPatrick Mooney 		if ((val & VIRTIO_NET_F_GUEST_CSUM) == 0)
579b22a70abSPatrick Mooney 			val &= ~VIRTIO_NET_F_GUEST_TSO4;
580b22a70abSPatrick Mooney 
581b22a70abSPatrick Mooney 		link->l_features = val;
582b22a70abSPatrick Mooney 		break;
583b22a70abSPatrick Mooney 	case VNA_IOC_RING_INIT:
584b22a70abSPatrick Mooney 		err = viona_ioc_ring_init(link, dptr, md);
585b22a70abSPatrick Mooney 		break;
586b22a70abSPatrick Mooney 	case VNA_IOC_RING_RESET:
587b22a70abSPatrick Mooney 		err = viona_ioc_ring_reset(link, (uint_t)data);
588b22a70abSPatrick Mooney 		break;
589b22a70abSPatrick Mooney 	case VNA_IOC_RING_KICK:
590b22a70abSPatrick Mooney 		err = viona_ioc_ring_kick(link, (uint_t)data);
591b22a70abSPatrick Mooney 		break;
592b22a70abSPatrick Mooney 	case VNA_IOC_RING_SET_MSI:
593b22a70abSPatrick Mooney 		err = viona_ioc_ring_set_msi(link, dptr, md);
594b22a70abSPatrick Mooney 		break;
595b22a70abSPatrick Mooney 	case VNA_IOC_RING_INTR_CLR:
596b22a70abSPatrick Mooney 		err = viona_ioc_ring_intr_clear(link, (uint_t)data);
597b22a70abSPatrick Mooney 		break;
598a26f9c14SPatrick Mooney 	case VNA_IOC_RING_SET_STATE:
599a26f9c14SPatrick Mooney 		err = viona_ioc_ring_set_state(link, dptr, md);
600a26f9c14SPatrick Mooney 		break;
601a26f9c14SPatrick Mooney 	case VNA_IOC_RING_GET_STATE:
602a26f9c14SPatrick Mooney 		err = viona_ioc_ring_get_state(link, dptr, md);
603a26f9c14SPatrick Mooney 		break;
604a26f9c14SPatrick Mooney 	case VNA_IOC_RING_PAUSE:
605a26f9c14SPatrick Mooney 		err = viona_ioc_ring_pause(link, (uint_t)data);
606a26f9c14SPatrick Mooney 		break;
607a26f9c14SPatrick Mooney 
608b22a70abSPatrick Mooney 	case VNA_IOC_INTR_POLL:
609b22a70abSPatrick Mooney 		err = viona_ioc_intr_poll(link, dptr, md, rv);
610b22a70abSPatrick Mooney 		break;
611b22a70abSPatrick Mooney 	case VNA_IOC_SET_NOTIFY_IOP:
6120e1453c3SPatrick Mooney 		if (data < 0 || data > UINT16_MAX) {
6130e1453c3SPatrick Mooney 			err = EINVAL;
6140e1453c3SPatrick Mooney 			break;
6150e1453c3SPatrick Mooney 		}
6160e1453c3SPatrick Mooney 		err = viona_ioc_set_notify_ioport(link, (uint16_t)data);
617b22a70abSPatrick Mooney 		break;
618*d4221574SAndy Fiddaman 	case VNA_IOC_SET_PROMISC:
619*d4221574SAndy Fiddaman 		err = viona_ioc_set_promisc(link, (viona_promisc_t)data);
620*d4221574SAndy Fiddaman 		break;
621b22a70abSPatrick Mooney 	default:
622b22a70abSPatrick Mooney 		err = ENOTTY;
623b22a70abSPatrick Mooney 		break;
624b22a70abSPatrick Mooney 	}
625b22a70abSPatrick Mooney 
626b22a70abSPatrick Mooney 	mutex_exit(&ss->ss_lock);
627b22a70abSPatrick Mooney 	return (err);
628b22a70abSPatrick Mooney }
629b22a70abSPatrick Mooney 
630b22a70abSPatrick Mooney static int
viona_chpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)631b22a70abSPatrick Mooney viona_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
632b22a70abSPatrick Mooney     struct pollhead **phpp)
633b22a70abSPatrick Mooney {
634b22a70abSPatrick Mooney 	viona_soft_state_t *ss;
635b22a70abSPatrick Mooney 	viona_link_t *link;
636b22a70abSPatrick Mooney 
637b22a70abSPatrick Mooney 	ss = ddi_get_soft_state(viona_state, getminor(dev));
638b22a70abSPatrick Mooney 	if (ss == NULL) {
639b22a70abSPatrick Mooney 		return (ENXIO);
640b22a70abSPatrick Mooney 	}
641b22a70abSPatrick Mooney 
642b22a70abSPatrick Mooney 	mutex_enter(&ss->ss_lock);
643b22a70abSPatrick Mooney 	if ((link = ss->ss_link) == NULL || link->l_destroyed) {
644b22a70abSPatrick Mooney 		mutex_exit(&ss->ss_lock);
645b22a70abSPatrick Mooney 		return (ENXIO);
646b22a70abSPatrick Mooney 	}
647b22a70abSPatrick Mooney 
648b22a70abSPatrick Mooney 	*reventsp = 0;
649b22a70abSPatrick Mooney 	if ((events & POLLRDBAND) != 0) {
650b22a70abSPatrick Mooney 		for (uint_t i = 0; i < VIONA_VQ_MAX; i++) {
651b22a70abSPatrick Mooney 			if (link->l_vrings[i].vr_intr_enabled != 0) {
652b22a70abSPatrick Mooney 				*reventsp |= POLLRDBAND;
653b22a70abSPatrick Mooney 				break;
654b22a70abSPatrick Mooney 			}
655b22a70abSPatrick Mooney 		}
656b22a70abSPatrick Mooney 	}
657b22a70abSPatrick Mooney 	if ((*reventsp == 0 && !anyyet) || (events & POLLET)) {
658b22a70abSPatrick Mooney 		*phpp = &link->l_pollhead;
659b22a70abSPatrick Mooney 	}
660b22a70abSPatrick Mooney 	mutex_exit(&ss->ss_lock);
661b22a70abSPatrick Mooney 
662b22a70abSPatrick Mooney 	return (0);
663b22a70abSPatrick Mooney }
664b22a70abSPatrick Mooney 
665b22a70abSPatrick Mooney static void
viona_get_mac_capab(viona_link_t * link)666b22a70abSPatrick Mooney viona_get_mac_capab(viona_link_t *link)
667b22a70abSPatrick Mooney {
668b22a70abSPatrick Mooney 	mac_handle_t mh = link->l_mh;
669b22a70abSPatrick Mooney 	uint32_t cap = 0;
670b22a70abSPatrick Mooney 	mac_capab_lso_t lso_cap;
671b22a70abSPatrick Mooney 
672b22a70abSPatrick Mooney 	link->l_features_hw = 0;
673b22a70abSPatrick Mooney 	if (mac_capab_get(mh, MAC_CAPAB_HCKSUM, &cap)) {
674b22a70abSPatrick Mooney 		/*
675b22a70abSPatrick Mooney 		 * Only report HW checksum ability if the underlying MAC
676b22a70abSPatrick Mooney 		 * resource is capable of populating the L4 header.
677b22a70abSPatrick Mooney 		 */
678b22a70abSPatrick Mooney 		if ((cap & VIONA_CAP_HCKSUM_INTEREST) != 0) {
679b22a70abSPatrick Mooney 			link->l_features_hw |= VIRTIO_NET_F_CSUM;
680b22a70abSPatrick Mooney 		}
681b22a70abSPatrick Mooney 		link->l_cap_csum = cap;
682b22a70abSPatrick Mooney 	}
683b22a70abSPatrick Mooney 
684b22a70abSPatrick Mooney 	if ((link->l_features_hw & VIRTIO_NET_F_CSUM) &&
685b22a70abSPatrick Mooney 	    mac_capab_get(mh, MAC_CAPAB_LSO, &lso_cap)) {
686b22a70abSPatrick Mooney 		/*
687b22a70abSPatrick Mooney 		 * Virtio doesn't allow for negotiating a maximum LSO
688b22a70abSPatrick Mooney 		 * packet size. We have to assume that the guest may
689b22a70abSPatrick Mooney 		 * send a maximum length IP packet. Make sure the
690b22a70abSPatrick Mooney 		 * underlying MAC can handle an LSO of this size.
691b22a70abSPatrick Mooney 		 */
692b22a70abSPatrick Mooney 		if ((lso_cap.lso_flags & LSO_TX_BASIC_TCP_IPV4) &&
693b22a70abSPatrick Mooney 		    lso_cap.lso_basic_tcp_ipv4.lso_max >= IP_MAXPACKET)
694b22a70abSPatrick Mooney 			link->l_features_hw |= VIRTIO_NET_F_HOST_TSO4;
695b22a70abSPatrick Mooney 	}
696b22a70abSPatrick Mooney }
697b22a70abSPatrick Mooney 
698b22a70abSPatrick Mooney static int
viona_ioc_create(viona_soft_state_t * ss,void * dptr,int md,cred_t * cr)699b22a70abSPatrick Mooney viona_ioc_create(viona_soft_state_t *ss, void *dptr, int md, cred_t *cr)
700b22a70abSPatrick Mooney {
701b22a70abSPatrick Mooney 	vioc_create_t	kvc;
702b22a70abSPatrick Mooney 	viona_link_t	*link = NULL;
703b22a70abSPatrick Mooney 	char		cli_name[MAXNAMELEN];
704b22a70abSPatrick Mooney 	int		err = 0;
705b22a70abSPatrick Mooney 	file_t		*fp;
706b22a70abSPatrick Mooney 	vmm_hold_t	*hold = NULL;
707b22a70abSPatrick Mooney 	viona_neti_t	*nip = NULL;
708b22a70abSPatrick Mooney 	zoneid_t	zid;
7091165c309SLuqman Aden 	mac_diag_t	mac_diag = MAC_DIAG_NONE;
710b22a70abSPatrick Mooney 
711b22a70abSPatrick Mooney 	ASSERT(MUTEX_NOT_HELD(&ss->ss_lock));
712b22a70abSPatrick Mooney 
713b22a70abSPatrick Mooney 	if (ddi_copyin(dptr, &kvc, sizeof (kvc), md) != 0) {
714b22a70abSPatrick Mooney 		return (EFAULT);
715b22a70abSPatrick Mooney 	}
716b22a70abSPatrick Mooney 
717b22a70abSPatrick Mooney 	zid = crgetzoneid(cr);
718b22a70abSPatrick Mooney 	nip = viona_neti_lookup_by_zid(zid);
719b22a70abSPatrick Mooney 	if (nip == NULL) {
720b22a70abSPatrick Mooney 		return (EIO);
721b22a70abSPatrick Mooney 	}
722b22a70abSPatrick Mooney 
723b22a70abSPatrick Mooney 	if (!nip->vni_nethook.vnh_hooked) {
724b22a70abSPatrick Mooney 		viona_neti_rele(nip);
725b22a70abSPatrick Mooney 		return (EIO);
726b22a70abSPatrick Mooney 	}
727b22a70abSPatrick Mooney 
728b22a70abSPatrick Mooney 	mutex_enter(&ss->ss_lock);
729b22a70abSPatrick Mooney 	if (ss->ss_link != NULL) {
730b22a70abSPatrick Mooney 		mutex_exit(&ss->ss_lock);
731b22a70abSPatrick Mooney 		viona_neti_rele(nip);
732b22a70abSPatrick Mooney 		return (EEXIST);
733b22a70abSPatrick Mooney 	}
734b22a70abSPatrick Mooney 
735b22a70abSPatrick Mooney 	if ((fp = getf(kvc.c_vmfd)) == NULL) {
736b22a70abSPatrick Mooney 		err = EBADF;
737b22a70abSPatrick Mooney 		goto bail;
738b22a70abSPatrick Mooney 	}
739b22a70abSPatrick Mooney 	err = vmm_drv_hold(fp, cr, &hold);
740b22a70abSPatrick Mooney 	releasef(kvc.c_vmfd);
741b22a70abSPatrick Mooney 	if (err != 0) {
742b22a70abSPatrick Mooney 		goto bail;
743b22a70abSPatrick Mooney 	}
744b22a70abSPatrick Mooney 
745b22a70abSPatrick Mooney 	link = kmem_zalloc(sizeof (viona_link_t), KM_SLEEP);
746b22a70abSPatrick Mooney 	link->l_linkid = kvc.c_linkid;
747b22a70abSPatrick Mooney 	link->l_vm_hold = hold;
748b22a70abSPatrick Mooney 
749b22a70abSPatrick Mooney 	err = mac_open_by_linkid(link->l_linkid, &link->l_mh);
750b22a70abSPatrick Mooney 	if (err != 0) {
751b22a70abSPatrick Mooney 		goto bail;
752b22a70abSPatrick Mooney 	}
753b22a70abSPatrick Mooney 
754b22a70abSPatrick Mooney 	viona_get_mac_capab(link);
755b22a70abSPatrick Mooney 
756b22a70abSPatrick Mooney 	(void) snprintf(cli_name, sizeof (cli_name), "%s-%d", VIONA_CLI_NAME,
757b22a70abSPatrick Mooney 	    link->l_linkid);
758b22a70abSPatrick Mooney 	err = mac_client_open(link->l_mh, &link->l_mch, cli_name, 0);
759b22a70abSPatrick Mooney 	if (err != 0) {
760b22a70abSPatrick Mooney 		goto bail;
761b22a70abSPatrick Mooney 	}
762b22a70abSPatrick Mooney 
7631165c309SLuqman Aden 	err = mac_unicast_add(link->l_mch, NULL, MAC_UNICAST_PRIMARY,
7641165c309SLuqman Aden 	    &link->l_muh, VLAN_ID_NONE, &mac_diag);
7651165c309SLuqman Aden 	if (err != 0) {
7661165c309SLuqman Aden 		goto bail;
7671165c309SLuqman Aden 	}
7681165c309SLuqman Aden 
769b22a70abSPatrick Mooney 	viona_ring_alloc(link, &link->l_vrings[VIONA_VQ_RX]);
770b22a70abSPatrick Mooney 	viona_ring_alloc(link, &link->l_vrings[VIONA_VQ_TX]);
771b22a70abSPatrick Mooney 
772*d4221574SAndy Fiddaman 	/*
773*d4221574SAndy Fiddaman 	 * Default to passing up all multicast traffic in addition to
774*d4221574SAndy Fiddaman 	 * classified unicast. Guests which have support will change this
775*d4221574SAndy Fiddaman 	 * if they need to via the virtio net control queue; guests without
776*d4221574SAndy Fiddaman 	 * support generally still want to see multicast.
777*d4221574SAndy Fiddaman 	 */
778*d4221574SAndy Fiddaman 	link->l_promisc = VIONA_PROMISC_MULTI;
779*d4221574SAndy Fiddaman 	if ((err = viona_rx_set(link, link->l_promisc)) != 0) {
780*d4221574SAndy Fiddaman 		viona_rx_clear(link);
781b22a70abSPatrick Mooney 		viona_ring_free(&link->l_vrings[VIONA_VQ_RX]);
782b22a70abSPatrick Mooney 		viona_ring_free(&link->l_vrings[VIONA_VQ_TX]);
783b22a70abSPatrick Mooney 		goto bail;
784b22a70abSPatrick Mooney 	}
785b22a70abSPatrick Mooney 
786b22a70abSPatrick Mooney 	link->l_neti = nip;
787b22a70abSPatrick Mooney 	ss->ss_link = link;
788b22a70abSPatrick Mooney 	mutex_exit(&ss->ss_lock);
789b22a70abSPatrick Mooney 
790b22a70abSPatrick Mooney 	mutex_enter(&nip->vni_lock);
791b22a70abSPatrick Mooney 	list_insert_tail(&nip->vni_dev_list, ss);
792b22a70abSPatrick Mooney 	mutex_exit(&nip->vni_lock);
793b22a70abSPatrick Mooney 
794b22a70abSPatrick Mooney 	return (0);
795b22a70abSPatrick Mooney 
796b22a70abSPatrick Mooney bail:
797b22a70abSPatrick Mooney 	if (link != NULL) {
798b22a70abSPatrick Mooney 		if (link->l_mch != NULL) {
7991165c309SLuqman Aden 			if (link->l_muh != NULL) {
8001165c309SLuqman Aden 				VERIFY0(mac_unicast_remove(link->l_mch,
8011165c309SLuqman Aden 				    link->l_muh));
8021165c309SLuqman Aden 				link->l_muh = NULL;
8031165c309SLuqman Aden 			}
804b22a70abSPatrick Mooney 			mac_client_close(link->l_mch, 0);
805b22a70abSPatrick Mooney 		}
806b22a70abSPatrick Mooney 		if (link->l_mh != NULL) {
807b22a70abSPatrick Mooney 			mac_close(link->l_mh);
808b22a70abSPatrick Mooney 		}
809b22a70abSPatrick Mooney 		kmem_free(link, sizeof (viona_link_t));
810b22a70abSPatrick Mooney 	}
811b22a70abSPatrick Mooney 	if (hold != NULL) {
812b22a70abSPatrick Mooney 		vmm_drv_rele(hold);
813b22a70abSPatrick Mooney 	}
814b22a70abSPatrick Mooney 	viona_neti_rele(nip);
815b22a70abSPatrick Mooney 
816b22a70abSPatrick Mooney 	mutex_exit(&ss->ss_lock);
817b22a70abSPatrick Mooney 	return (err);
818b22a70abSPatrick Mooney }
819b22a70abSPatrick Mooney 
820b22a70abSPatrick Mooney static int
viona_ioc_delete(viona_soft_state_t * ss,boolean_t on_close)821b22a70abSPatrick Mooney viona_ioc_delete(viona_soft_state_t *ss, boolean_t on_close)
822b22a70abSPatrick Mooney {
823b22a70abSPatrick Mooney 	viona_link_t *link;
824b22a70abSPatrick Mooney 	viona_neti_t *nip = NULL;
825b22a70abSPatrick Mooney 
826b22a70abSPatrick Mooney 	mutex_enter(&ss->ss_lock);
827b22a70abSPatrick Mooney 	if ((link = ss->ss_link) == NULL) {
828b22a70abSPatrick Mooney 		/* Link destruction already complete */
829b22a70abSPatrick Mooney 		mutex_exit(&ss->ss_lock);
830b22a70abSPatrick Mooney 		return (0);
831b22a70abSPatrick Mooney 	}
832b22a70abSPatrick Mooney 
833b22a70abSPatrick Mooney 	if (link->l_destroyed) {
834b22a70abSPatrick Mooney 		/*
835b22a70abSPatrick Mooney 		 * Link destruction has been started by another thread, but has
836b22a70abSPatrick Mooney 		 * not completed.  This condition should be impossible to
837b22a70abSPatrick Mooney 		 * encounter when performing the on-close destroy of the link,
838b22a70abSPatrick Mooney 		 * since racing ioctl accessors must necessarily be absent.
839b22a70abSPatrick Mooney 		 */
840b22a70abSPatrick Mooney 		VERIFY(!on_close);
841b22a70abSPatrick Mooney 		mutex_exit(&ss->ss_lock);
842b22a70abSPatrick Mooney 		return (EAGAIN);
843b22a70abSPatrick Mooney 	}
844b22a70abSPatrick Mooney 	/*
845b22a70abSPatrick Mooney 	 * The link deletion cannot fail after this point, continuing until its
846b22a70abSPatrick Mooney 	 * successful completion is reached.
847b22a70abSPatrick Mooney 	 */
848b22a70abSPatrick Mooney 	link->l_destroyed = B_TRUE;
849b22a70abSPatrick Mooney 
850b22a70abSPatrick Mooney 	/*
851b22a70abSPatrick Mooney 	 * Tear down the IO port hook so it cannot be used to kick any of the
852b22a70abSPatrick Mooney 	 * rings which are about to be reset and stopped.
853b22a70abSPatrick Mooney 	 */
854b22a70abSPatrick Mooney 	VERIFY0(viona_ioc_set_notify_ioport(link, 0));
855b22a70abSPatrick Mooney 	mutex_exit(&ss->ss_lock);
856b22a70abSPatrick Mooney 
857b22a70abSPatrick Mooney 	/*
858b22a70abSPatrick Mooney 	 * Return the rings to their reset state, ignoring any possible
859b22a70abSPatrick Mooney 	 * interruptions from signals.
860b22a70abSPatrick Mooney 	 */
861b22a70abSPatrick Mooney 	VERIFY0(viona_ring_reset(&link->l_vrings[VIONA_VQ_RX], B_FALSE));
862b22a70abSPatrick Mooney 	VERIFY0(viona_ring_reset(&link->l_vrings[VIONA_VQ_TX], B_FALSE));
863b22a70abSPatrick Mooney 
864b22a70abSPatrick Mooney 	mutex_enter(&ss->ss_lock);
865b22a70abSPatrick Mooney 	if (link->l_mch != NULL) {
866b22a70abSPatrick Mooney 		/* Unhook the receive callbacks and close out the client */
867b22a70abSPatrick Mooney 		viona_rx_clear(link);
8681165c309SLuqman Aden 		if (link->l_muh != NULL) {
8691165c309SLuqman Aden 			VERIFY0(mac_unicast_remove(link->l_mch, link->l_muh));
8701165c309SLuqman Aden 			link->l_muh = NULL;
8711165c309SLuqman Aden 		}
872b22a70abSPatrick Mooney 		mac_client_close(link->l_mch, 0);
873b22a70abSPatrick Mooney 	}
874b22a70abSPatrick Mooney 	if (link->l_mh != NULL) {
875b22a70abSPatrick Mooney 		mac_close(link->l_mh);
876b22a70abSPatrick Mooney 	}
877b22a70abSPatrick Mooney 	if (link->l_vm_hold != NULL) {
878b22a70abSPatrick Mooney 		vmm_drv_rele(link->l_vm_hold);
879b22a70abSPatrick Mooney 		link->l_vm_hold = NULL;
880b22a70abSPatrick Mooney 	}
881b22a70abSPatrick Mooney 
882b22a70abSPatrick Mooney 	nip = link->l_neti;
883b22a70abSPatrick Mooney 	link->l_neti = NULL;
884b22a70abSPatrick Mooney 
885b22a70abSPatrick Mooney 	viona_ring_free(&link->l_vrings[VIONA_VQ_RX]);
886b22a70abSPatrick Mooney 	viona_ring_free(&link->l_vrings[VIONA_VQ_TX]);
887b22a70abSPatrick Mooney 	pollhead_clean(&link->l_pollhead);
888b22a70abSPatrick Mooney 	ss->ss_link = NULL;
889b22a70abSPatrick Mooney 	mutex_exit(&ss->ss_lock);
890b22a70abSPatrick Mooney 
891b22a70abSPatrick Mooney 	mutex_enter(&nip->vni_lock);
892b22a70abSPatrick Mooney 	list_remove(&nip->vni_dev_list, ss);
893b22a70abSPatrick Mooney 	mutex_exit(&nip->vni_lock);
894b22a70abSPatrick Mooney 
895b22a70abSPatrick Mooney 	viona_neti_rele(nip);
896b22a70abSPatrick Mooney 
897b22a70abSPatrick Mooney 	kmem_free(link, sizeof (viona_link_t));
898b22a70abSPatrick Mooney 	return (0);
899b22a70abSPatrick Mooney }
900b22a70abSPatrick Mooney 
901b22a70abSPatrick Mooney static int
viona_ioc_ring_init(viona_link_t * link,void * udata,int md)902b22a70abSPatrick Mooney viona_ioc_ring_init(viona_link_t *link, void *udata, int md)
903b22a70abSPatrick Mooney {
904b22a70abSPatrick Mooney 	vioc_ring_init_t kri;
905b22a70abSPatrick Mooney 	int err;
906b22a70abSPatrick Mooney 
907b22a70abSPatrick Mooney 	if (ddi_copyin(udata, &kri, sizeof (kri), md) != 0) {
908b22a70abSPatrick Mooney 		return (EFAULT);
909b22a70abSPatrick Mooney 	}
910a26f9c14SPatrick Mooney 	const struct viona_ring_params params = {
911a26f9c14SPatrick Mooney 		.vrp_pa = kri.ri_qaddr,
912a26f9c14SPatrick Mooney 		.vrp_size = kri.ri_qsize,
913a26f9c14SPatrick Mooney 		.vrp_avail_idx = 0,
914a26f9c14SPatrick Mooney 		.vrp_used_idx = 0,
915a26f9c14SPatrick Mooney 	};
916a26f9c14SPatrick Mooney 
917a26f9c14SPatrick Mooney 	err = viona_ring_init(link, kri.ri_index, &params);
918a26f9c14SPatrick Mooney 
919a26f9c14SPatrick Mooney 	return (err);
920a26f9c14SPatrick Mooney }
921a26f9c14SPatrick Mooney 
922a26f9c14SPatrick Mooney static int
viona_ioc_ring_set_state(viona_link_t * link,void * udata,int md)923a26f9c14SPatrick Mooney viona_ioc_ring_set_state(viona_link_t *link, void *udata, int md)
924a26f9c14SPatrick Mooney {
925a26f9c14SPatrick Mooney 	vioc_ring_state_t krs;
926a26f9c14SPatrick Mooney 	int err;
927a26f9c14SPatrick Mooney 
928a26f9c14SPatrick Mooney 	if (ddi_copyin(udata, &krs, sizeof (krs), md) != 0) {
929a26f9c14SPatrick Mooney 		return (EFAULT);
930a26f9c14SPatrick Mooney 	}
931a26f9c14SPatrick Mooney 	const struct viona_ring_params params = {
932a26f9c14SPatrick Mooney 		.vrp_pa = krs.vrs_qaddr,
933a26f9c14SPatrick Mooney 		.vrp_size = krs.vrs_qsize,
934a26f9c14SPatrick Mooney 		.vrp_avail_idx = krs.vrs_avail_idx,
935a26f9c14SPatrick Mooney 		.vrp_used_idx = krs.vrs_used_idx,
936a26f9c14SPatrick Mooney 	};
937b22a70abSPatrick Mooney 
938a26f9c14SPatrick Mooney 	err = viona_ring_init(link, krs.vrs_index, &params);
939b22a70abSPatrick Mooney 
940b22a70abSPatrick Mooney 	return (err);
941b22a70abSPatrick Mooney }
942b22a70abSPatrick Mooney 
943a26f9c14SPatrick Mooney static int
viona_ioc_ring_get_state(viona_link_t * link,void * udata,int md)944a26f9c14SPatrick Mooney viona_ioc_ring_get_state(viona_link_t *link, void *udata, int md)
945a26f9c14SPatrick Mooney {
946a26f9c14SPatrick Mooney 	vioc_ring_state_t krs;
947a26f9c14SPatrick Mooney 
948a26f9c14SPatrick Mooney 	if (ddi_copyin(udata, &krs, sizeof (krs), md) != 0) {
949a26f9c14SPatrick Mooney 		return (EFAULT);
950a26f9c14SPatrick Mooney 	}
951a26f9c14SPatrick Mooney 
952a26f9c14SPatrick Mooney 	struct viona_ring_params params;
953a26f9c14SPatrick Mooney 	int err = viona_ring_get_state(link, krs.vrs_index, &params);
954a26f9c14SPatrick Mooney 	if (err != 0) {
955a26f9c14SPatrick Mooney 		return (err);
956a26f9c14SPatrick Mooney 	}
957a26f9c14SPatrick Mooney 	krs.vrs_qsize = params.vrp_size;
958a26f9c14SPatrick Mooney 	krs.vrs_qaddr = params.vrp_pa;
959a26f9c14SPatrick Mooney 	krs.vrs_avail_idx = params.vrp_avail_idx;
960a26f9c14SPatrick Mooney 	krs.vrs_used_idx = params.vrp_used_idx;
961a26f9c14SPatrick Mooney 
962a26f9c14SPatrick Mooney 	if (ddi_copyout(&krs, udata, sizeof (krs), md) != 0) {
963a26f9c14SPatrick Mooney 		return (EFAULT);
964a26f9c14SPatrick Mooney 	}
965a26f9c14SPatrick Mooney 	return (0);
966a26f9c14SPatrick Mooney }
967a26f9c14SPatrick Mooney 
968b22a70abSPatrick Mooney static int
viona_ioc_ring_reset(viona_link_t * link,uint_t idx)969b22a70abSPatrick Mooney viona_ioc_ring_reset(viona_link_t *link, uint_t idx)
970b22a70abSPatrick Mooney {
971b22a70abSPatrick Mooney 	viona_vring_t *ring;
972b22a70abSPatrick Mooney 
973b22a70abSPatrick Mooney 	if (idx >= VIONA_VQ_MAX) {
974b22a70abSPatrick Mooney 		return (EINVAL);
975b22a70abSPatrick Mooney 	}
976b22a70abSPatrick Mooney 	ring = &link->l_vrings[idx];
977b22a70abSPatrick Mooney 
978b22a70abSPatrick Mooney 	return (viona_ring_reset(ring, B_TRUE));
979b22a70abSPatrick Mooney }
980b22a70abSPatrick Mooney 
981b22a70abSPatrick Mooney static int
viona_ioc_ring_kick(viona_link_t * link,uint_t idx)982b22a70abSPatrick Mooney viona_ioc_ring_kick(viona_link_t *link, uint_t idx)
983b22a70abSPatrick Mooney {
984b22a70abSPatrick Mooney 	viona_vring_t *ring;
985b22a70abSPatrick Mooney 	int err;
986b22a70abSPatrick Mooney 
987b22a70abSPatrick Mooney 	if (idx >= VIONA_VQ_MAX) {
988b22a70abSPatrick Mooney 		return (EINVAL);
989b22a70abSPatrick Mooney 	}
990b22a70abSPatrick Mooney 	ring = &link->l_vrings[idx];
991b22a70abSPatrick Mooney 
992b22a70abSPatrick Mooney 	mutex_enter(&ring->vr_lock);
993b22a70abSPatrick Mooney 	switch (ring->vr_state) {
994b22a70abSPatrick Mooney 	case VRS_SETUP:
995b22a70abSPatrick Mooney 		/*
996b22a70abSPatrick Mooney 		 * An early kick to a ring which is starting its worker thread
997b22a70abSPatrick Mooney 		 * is fine.  Once that thread is active, it will process the
998b22a70abSPatrick Mooney 		 * start-up request immediately.
999b22a70abSPatrick Mooney 		 */
1000b22a70abSPatrick Mooney 		/* FALLTHROUGH */
1001b22a70abSPatrick Mooney 	case VRS_INIT:
1002b22a70abSPatrick Mooney 		ring->vr_state_flags |= VRSF_REQ_START;
1003b22a70abSPatrick Mooney 		/* FALLTHROUGH */
1004b22a70abSPatrick Mooney 	case VRS_RUN:
1005b22a70abSPatrick Mooney 		cv_broadcast(&ring->vr_cv);
1006b22a70abSPatrick Mooney 		err = 0;
1007b22a70abSPatrick Mooney 		break;
1008b22a70abSPatrick Mooney 	default:
1009b22a70abSPatrick Mooney 		err = EBUSY;
1010b22a70abSPatrick Mooney 		break;
1011b22a70abSPatrick Mooney 	}
1012b22a70abSPatrick Mooney 	mutex_exit(&ring->vr_lock);
1013b22a70abSPatrick Mooney 
1014b22a70abSPatrick Mooney 	return (err);
1015b22a70abSPatrick Mooney }
1016b22a70abSPatrick Mooney 
1017a26f9c14SPatrick Mooney static int
viona_ioc_ring_pause(viona_link_t * link,uint_t idx)1018a26f9c14SPatrick Mooney viona_ioc_ring_pause(viona_link_t *link, uint_t idx)
1019a26f9c14SPatrick Mooney {
1020a26f9c14SPatrick Mooney 	if (idx >= VIONA_VQ_MAX) {
1021a26f9c14SPatrick Mooney 		return (EINVAL);
1022a26f9c14SPatrick Mooney 	}
1023a26f9c14SPatrick Mooney 
1024a26f9c14SPatrick Mooney 	viona_vring_t *ring = &link->l_vrings[idx];
1025a26f9c14SPatrick Mooney 	return (viona_ring_pause(ring));
1026a26f9c14SPatrick Mooney }
1027a26f9c14SPatrick Mooney 
1028b22a70abSPatrick Mooney static int
viona_ioc_ring_set_msi(viona_link_t * link,void * data,int md)1029b22a70abSPatrick Mooney viona_ioc_ring_set_msi(viona_link_t *link, void *data, int md)
1030b22a70abSPatrick Mooney {
1031b22a70abSPatrick Mooney 	vioc_ring_msi_t vrm;
1032b22a70abSPatrick Mooney 	viona_vring_t *ring;
1033b22a70abSPatrick Mooney 
1034b22a70abSPatrick Mooney 	if (ddi_copyin(data, &vrm, sizeof (vrm), md) != 0) {
1035b22a70abSPatrick Mooney 		return (EFAULT);
1036b22a70abSPatrick Mooney 	}
1037b22a70abSPatrick Mooney 	if (vrm.rm_index >= VIONA_VQ_MAX) {
1038b22a70abSPatrick Mooney 		return (EINVAL);
1039b22a70abSPatrick Mooney 	}
1040b22a70abSPatrick Mooney 
1041b22a70abSPatrick Mooney 	ring = &link->l_vrings[vrm.rm_index];
1042b22a70abSPatrick Mooney 	mutex_enter(&ring->vr_lock);
1043b22a70abSPatrick Mooney 	ring->vr_msi_addr = vrm.rm_addr;
1044b22a70abSPatrick Mooney 	ring->vr_msi_msg = vrm.rm_msg;
1045b22a70abSPatrick Mooney 	mutex_exit(&ring->vr_lock);
1046b22a70abSPatrick Mooney 
1047b22a70abSPatrick Mooney 	return (0);
1048b22a70abSPatrick Mooney }
1049b22a70abSPatrick Mooney 
1050b22a70abSPatrick Mooney static int
viona_notify_iop(void * arg,bool in,uint16_t port,uint8_t bytes,uint32_t * val)10510e1453c3SPatrick Mooney viona_notify_iop(void *arg, bool in, uint16_t port, uint8_t bytes,
10520e1453c3SPatrick Mooney     uint32_t *val)
1053b22a70abSPatrick Mooney {
1054b22a70abSPatrick Mooney 	viona_link_t *link = (viona_link_t *)arg;
10550e1453c3SPatrick Mooney 
1056a26f9c14SPatrick Mooney 	/*
1057a26f9c14SPatrick Mooney 	 * If the request is a read (in/ins), or direct at a port other than
1058a26f9c14SPatrick Mooney 	 * what we expect to be registered on, ignore it.
1059a26f9c14SPatrick Mooney 	 */
1060a26f9c14SPatrick Mooney 	if (in || port != link->l_notify_ioport) {
10610e1453c3SPatrick Mooney 		return (ESRCH);
10620e1453c3SPatrick Mooney 	}
1063b22a70abSPatrick Mooney 
1064a26f9c14SPatrick Mooney 	/* Let userspace handle notifications for rings other than RX/TX. */
1065a26f9c14SPatrick Mooney 	const uint16_t vq = *val;
1066a26f9c14SPatrick Mooney 	if (vq >= VIONA_VQ_MAX) {
1067a26f9c14SPatrick Mooney 		return (ESRCH);
1068b22a70abSPatrick Mooney 	}
1069a26f9c14SPatrick Mooney 
1070a26f9c14SPatrick Mooney 	viona_vring_t *ring = &link->l_vrings[vq];
1071a26f9c14SPatrick Mooney 	int res = 0;
1072a26f9c14SPatrick Mooney 
1073a26f9c14SPatrick Mooney 	mutex_enter(&ring->vr_lock);
1074a26f9c14SPatrick Mooney 	if (ring->vr_state == VRS_RUN) {
1075a26f9c14SPatrick Mooney 		cv_broadcast(&ring->vr_cv);
1076a26f9c14SPatrick Mooney 	} else {
1077a26f9c14SPatrick Mooney 		res = ESRCH;
1078a26f9c14SPatrick Mooney 	}
1079a26f9c14SPatrick Mooney 	mutex_exit(&ring->vr_lock);
1080a26f9c14SPatrick Mooney 
1081a26f9c14SPatrick Mooney 	return (res);
1082b22a70abSPatrick Mooney }
1083b22a70abSPatrick Mooney 
1084b22a70abSPatrick Mooney static int
viona_ioc_set_notify_ioport(viona_link_t * link,uint16_t ioport)10850e1453c3SPatrick Mooney viona_ioc_set_notify_ioport(viona_link_t *link, uint16_t ioport)
1086b22a70abSPatrick Mooney {
1087b22a70abSPatrick Mooney 	int err = 0;
1088b22a70abSPatrick Mooney 
1089b22a70abSPatrick Mooney 	if (link->l_notify_ioport != 0) {
1090b22a70abSPatrick Mooney 		vmm_drv_ioport_unhook(link->l_vm_hold, &link->l_notify_cookie);
1091b22a70abSPatrick Mooney 		link->l_notify_ioport = 0;
1092b22a70abSPatrick Mooney 	}
1093b22a70abSPatrick Mooney 
1094b22a70abSPatrick Mooney 	if (ioport != 0) {
10950e1453c3SPatrick Mooney 		err = vmm_drv_ioport_hook(link->l_vm_hold, ioport,
10960e1453c3SPatrick Mooney 		    viona_notify_iop, (void *)link, &link->l_notify_cookie);
1097b22a70abSPatrick Mooney 		if (err == 0) {
1098b22a70abSPatrick Mooney 			link->l_notify_ioport = ioport;
1099b22a70abSPatrick Mooney 		}
1100b22a70abSPatrick Mooney 	}
1101b22a70abSPatrick Mooney 	return (err);
1102b22a70abSPatrick Mooney }
1103b22a70abSPatrick Mooney 
1104*d4221574SAndy Fiddaman static int
viona_ioc_set_promisc(viona_link_t * link,viona_promisc_t mode)1105*d4221574SAndy Fiddaman viona_ioc_set_promisc(viona_link_t *link, viona_promisc_t mode)
1106*d4221574SAndy Fiddaman {
1107*d4221574SAndy Fiddaman 	int err;
1108*d4221574SAndy Fiddaman 
1109*d4221574SAndy Fiddaman 	if (mode >= VIONA_PROMISC_MAX) {
1110*d4221574SAndy Fiddaman 		return (EINVAL);
1111*d4221574SAndy Fiddaman 	}
1112*d4221574SAndy Fiddaman 
1113*d4221574SAndy Fiddaman 	if (mode == link->l_promisc) {
1114*d4221574SAndy Fiddaman 		return (0);
1115*d4221574SAndy Fiddaman 	}
1116*d4221574SAndy Fiddaman 
1117*d4221574SAndy Fiddaman 	if ((err = viona_rx_set(link, mode)) != 0) {
1118*d4221574SAndy Fiddaman 		return (err);
1119*d4221574SAndy Fiddaman 	}
1120*d4221574SAndy Fiddaman 
1121*d4221574SAndy Fiddaman 	link->l_promisc = mode;
1122*d4221574SAndy Fiddaman 	return (0);
1123*d4221574SAndy Fiddaman }
1124*d4221574SAndy Fiddaman 
1125b22a70abSPatrick Mooney static int
viona_ioc_ring_intr_clear(viona_link_t * link,uint_t idx)1126b22a70abSPatrick Mooney viona_ioc_ring_intr_clear(viona_link_t *link, uint_t idx)
1127b22a70abSPatrick Mooney {
1128b22a70abSPatrick Mooney 	if (idx >= VIONA_VQ_MAX) {
1129b22a70abSPatrick Mooney 		return (EINVAL);
1130b22a70abSPatrick Mooney 	}
1131b22a70abSPatrick Mooney 
1132b22a70abSPatrick Mooney 	link->l_vrings[idx].vr_intr_enabled = 0;
1133b22a70abSPatrick Mooney 	return (0);
1134b22a70abSPatrick Mooney }
1135b22a70abSPatrick Mooney 
1136b22a70abSPatrick Mooney static int
viona_ioc_intr_poll(viona_link_t * link,void * udata,int md,int * rv)1137b22a70abSPatrick Mooney viona_ioc_intr_poll(viona_link_t *link, void *udata, int md, int *rv)
1138b22a70abSPatrick Mooney {
1139b22a70abSPatrick Mooney 	uint_t cnt = 0;
1140b22a70abSPatrick Mooney 	vioc_intr_poll_t vip;
1141b22a70abSPatrick Mooney 
1142b22a70abSPatrick Mooney 	for (uint_t i = 0; i < VIONA_VQ_MAX; i++) {
1143b22a70abSPatrick Mooney 		uint_t val = link->l_vrings[i].vr_intr_enabled;
1144b22a70abSPatrick Mooney 
1145b22a70abSPatrick Mooney 		vip.vip_status[i] = val;
1146b22a70abSPatrick Mooney 		if (val != 0) {
1147b22a70abSPatrick Mooney 			cnt++;
1148b22a70abSPatrick Mooney 		}
1149b22a70abSPatrick Mooney 	}
1150b22a70abSPatrick Mooney 
1151b22a70abSPatrick Mooney 	if (ddi_copyout(&vip, udata, sizeof (vip), md) != 0) {
1152b22a70abSPatrick Mooney 		return (EFAULT);
1153b22a70abSPatrick Mooney 	}
1154b22a70abSPatrick Mooney 	*rv = (int)cnt;
1155b22a70abSPatrick Mooney 	return (0);
1156b22a70abSPatrick Mooney }
1157