xref: /illumos-gate/usr/src/uts/intel/io/viona/viona_impl.h (revision a4955f4fa65e38d70c07d38e657a9aff43fa155f)
1 /*
2  * Copyright (c) 2013  Chris Torek <torek @ torek net>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 /*
27  * This file and its contents are supplied under the terms of the
28  * Common Development and Distribution License ("CDDL"), version 1.0.
29  * You may only use this file in accordance with the terms of version
30  * 1.0 of the CDDL.
31  *
32  * A full copy of the text of the CDDL should have accompanied this
33  * source.  A copy of the CDDL is also available via the Internet at
34  * http://www.illumos.org/license/CDDL.
35  *
36  * Copyright 2015 Pluribus Networks Inc.
37  * Copyright 2019 Joyent, Inc.
38  * Copyright 2023 Oxide Computer Company
39  */
40 
41 #ifndef	_VIONA_IMPL_H
42 #define	_VIONA_IMPL_H
43 
44 #include <sys/ddi.h>
45 #include <sys/list.h>
46 #include <sys/sunddi.h>
47 #include <sys/sunndi.h>
48 #include <sys/strsun.h>
49 #include <sys/sysmacros.h>
50 #include <sys/uio.h>
51 
52 #include <sys/mac_client.h>
53 #include <sys/mac_provider.h>
54 #include <sys/mac_client_priv.h>
55 #include <sys/neti.h>
56 #include <inet/ip.h>
57 #include <inet/tcp.h>
58 
59 #include <sys/vmm_drv.h>
60 #include <sys/viona_io.h>
61 
62 struct viona_link;
63 typedef struct viona_link viona_link_t;
64 struct viona_desb;
65 typedef struct viona_desb viona_desb_t;
66 struct viona_net;
67 typedef struct viona_neti viona_neti_t;
68 
69 enum viona_ring_state {
70 	VRS_RESET	= 0x0,	/* just allocated or reset */
71 	VRS_SETUP	= 0x1,	/* addrs setup and starting worker thread */
72 	VRS_INIT	= 0x2,	/* worker thread started & waiting to run */
73 	VRS_RUN		= 0x3,	/* running work routine */
74 	VRS_STOP	= 0x4,	/* worker is exiting */
75 };
76 enum viona_ring_state_flags {
77 	VRSF_REQ_START	= 0x1,	/* start running from INIT state */
78 	VRSF_REQ_STOP	= 0x2,	/* stop running, clean up, goto RESET state */
79 	VRSF_REQ_PAUSE	= 0x4,	/* stop running, goto INIT state */
80 	VRSF_RENEW	= 0x8,	/* ring renewing lease */
81 };
82 
83 typedef struct viona_vring {
84 	viona_link_t	*vr_link;
85 
86 	kmutex_t	vr_lock;
87 	kcondvar_t	vr_cv;
88 	uint16_t	vr_state;
89 	uint16_t	vr_state_flags;
90 	uint_t		vr_xfer_outstanding;
91 	kthread_t	*vr_worker_thread;
92 	vmm_lease_t	*vr_lease;
93 
94 	/* ring-sized resources for TX activity */
95 	viona_desb_t	*vr_txdesb;
96 	struct iovec	*vr_txiov;
97 
98 	uint_t		vr_intr_enabled;
99 	uint64_t	vr_msi_addr;
100 	uint64_t	vr_msi_msg;
101 
102 	/* Internal ring-related state */
103 	kmutex_t	vr_a_mutex;	/* sync consumers of 'avail' */
104 	kmutex_t	vr_u_mutex;	/* sync consumers of 'used' */
105 	uint64_t	vr_pa;
106 	uint16_t	vr_size;
107 	uint16_t	vr_mask;	/* cached from vr_size */
108 	uint16_t	vr_cur_aidx;	/* trails behind 'avail_idx' */
109 	uint16_t	vr_cur_uidx;	/* drives 'used_idx' */
110 
111 	/* Reference to guest pages holding virtqueue */
112 	void		**vr_map_pages;
113 	vmm_page_t	*vr_map_hold;
114 
115 	/* Per-ring error condition statistics */
116 	struct viona_ring_stats {
117 		uint64_t	rs_ndesc_too_high;
118 		uint64_t	rs_bad_idx;
119 		uint64_t	rs_indir_bad_len;
120 		uint64_t	rs_indir_bad_nest;
121 		uint64_t	rs_indir_bad_next;
122 		uint64_t	rs_no_space;
123 		uint64_t	rs_too_many_desc;
124 		uint64_t	rs_desc_bad_len;
125 
126 		uint64_t	rs_bad_ring_addr;
127 
128 		uint64_t	rs_fail_hcksum;
129 		uint64_t	rs_fail_hcksum6;
130 		uint64_t	rs_fail_hcksum_proto;
131 
132 		uint64_t	rs_bad_rx_frame;
133 		uint64_t	rs_rx_merge_overrun;
134 		uint64_t	rs_rx_merge_underrun;
135 		uint64_t	rs_rx_pad_short;
136 		uint64_t	rs_rx_mcast_check;
137 		uint64_t	rs_too_short;
138 		uint64_t	rs_tx_absent;
139 
140 		uint64_t	rs_rx_hookdrop;
141 		uint64_t	rs_tx_hookdrop;
142 	} vr_stats;
143 } viona_vring_t;
144 
145 struct viona_link {
146 	vmm_hold_t		*l_vm_hold;
147 	boolean_t		l_destroyed;
148 
149 	viona_vring_t		l_vrings[VIONA_VQ_MAX];
150 
151 	uint32_t		l_features;
152 	uint32_t		l_features_hw;
153 	uint32_t		l_cap_csum;
154 
155 	uint16_t		l_notify_ioport;
156 	void			*l_notify_cookie;
157 
158 	datalink_id_t		l_linkid;
159 	mac_handle_t		l_mh;
160 	mac_client_handle_t	l_mch;
161 	mac_promisc_handle_t	l_mph;
162 	mac_unicast_handle_t	l_muh;
163 
164 	pollhead_t		l_pollhead;
165 
166 	viona_neti_t		*l_neti;
167 };
168 
169 typedef struct viona_nethook {
170 	net_handle_t		vnh_neti;
171 	hook_family_t		vnh_family;
172 	hook_event_t		vnh_event_in;
173 	hook_event_t		vnh_event_out;
174 	hook_event_token_t	vnh_token_in;
175 	hook_event_token_t	vnh_token_out;
176 	boolean_t		vnh_hooked;
177 } viona_nethook_t;
178 
179 struct viona_neti {
180 	list_node_t		vni_node;
181 
182 	netid_t			vni_netid;
183 	zoneid_t		vni_zid;
184 
185 	viona_nethook_t		vni_nethook;
186 
187 	kmutex_t		vni_lock;	/* Protects remaining members */
188 	kcondvar_t		vni_ref_change; /* Protected by vni_lock */
189 	uint_t			vni_ref;	/* Protected by vni_lock */
190 	list_t			vni_dev_list;	/* Protected by vni_lock */
191 };
192 
193 typedef struct used_elem {
194 	uint16_t	id;
195 	uint32_t	len;
196 } used_elem_t;
197 
198 typedef struct viona_soft_state {
199 	kmutex_t		ss_lock;
200 	viona_link_t		*ss_link;
201 	list_node_t		ss_node;
202 } viona_soft_state_t;
203 
204 #pragma pack(1)
205 struct virtio_desc {
206 	uint64_t	vd_addr;
207 	uint32_t	vd_len;
208 	uint16_t	vd_flags;
209 	uint16_t	vd_next;
210 };
211 
212 struct virtio_used {
213 	uint32_t	vu_idx;
214 	uint32_t	vu_tlen;
215 };
216 
217 struct virtio_net_mrgrxhdr {
218 	uint8_t		vrh_flags;
219 	uint8_t		vrh_gso_type;
220 	uint16_t	vrh_hdr_len;
221 	uint16_t	vrh_gso_size;
222 	uint16_t	vrh_csum_start;
223 	uint16_t	vrh_csum_offset;
224 	uint16_t	vrh_bufs;
225 };
226 
227 struct virtio_net_hdr {
228 	uint8_t		vrh_flags;
229 	uint8_t		vrh_gso_type;
230 	uint16_t	vrh_hdr_len;
231 	uint16_t	vrh_gso_size;
232 	uint16_t	vrh_csum_start;
233 	uint16_t	vrh_csum_offset;
234 };
235 #pragma pack()
236 
237 #define	VNETHOOK_INTERESTED_IN(neti) \
238 	(neti)->vni_nethook.vnh_event_in.he_interested
239 #define	VNETHOOK_INTERESTED_OUT(neti) \
240 	(neti)->vni_nethook.vnh_event_out.he_interested
241 
242 
243 #define	VIONA_PROBE(name)	DTRACE_PROBE(viona__##name)
244 #define	VIONA_PROBE1(name, arg1, arg2)	\
245 	DTRACE_PROBE1(viona__##name, arg1, arg2)
246 #define	VIONA_PROBE2(name, arg1, arg2, arg3, arg4)	\
247 	DTRACE_PROBE2(viona__##name, arg1, arg2, arg3, arg4)
248 #define	VIONA_PROBE3(name, arg1, arg2, arg3, arg4, arg5, arg6)	\
249 	DTRACE_PROBE3(viona__##name, arg1, arg2, arg3, arg4, arg5, arg6)
250 #define	VIONA_PROBE5(name, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, \
251 	arg9, arg10) \
252 	DTRACE_PROBE5(viona__##name, arg1, arg2, arg3, arg4, arg5, arg6, arg7, \
253 	arg8, arg9, arg10)
254 #define	VIONA_PROBE_BAD_RING_ADDR(r, a)		\
255 	VIONA_PROBE2(bad_ring_addr, viona_vring_t *, r, void *, (void *)(a))
256 
257 #define	VIONA_RING_STAT_INCR(r, name)	\
258 	(((r)->vr_stats.rs_ ## name)++)
259 
260 
261 #define	VIONA_MAX_HDRS_LEN	(sizeof (struct ether_vlan_header) + \
262 	IP_MAX_HDR_LENGTH + TCP_MAX_HDR_LENGTH)
263 
264 #define	VRING_AVAIL_F_NO_INTERRUPT	1
265 #define	VRING_USED_F_NO_NOTIFY		1
266 
267 #define	VRING_DESC_F_NEXT	(1 << 0)
268 #define	VRING_DESC_F_WRITE	(1 << 1)
269 #define	VRING_DESC_F_INDIRECT	(1 << 2)
270 
271 #define	VIRTIO_NET_HDR_F_NEEDS_CSUM	(1 << 0)
272 #define	VIRTIO_NET_HDR_F_DATA_VALID	(1 << 1)
273 
274 #define	VIRTIO_NET_HDR_GSO_NONE		0
275 #define	VIRTIO_NET_HDR_GSO_TCPV4	1
276 
277 #define	VIRTIO_NET_F_CSUM		(1 << 0)
278 #define	VIRTIO_NET_F_GUEST_CSUM		(1 << 1)
279 #define	VIRTIO_NET_F_MAC		(1 << 5) /* host supplies MAC */
280 #define	VIRTIO_NET_F_GUEST_TSO4		(1 << 7) /* guest can accept TSO */
281 #define	VIRTIO_NET_F_HOST_TSO4		(1 << 11) /* host can accept TSO */
282 #define	VIRTIO_NET_F_MRG_RXBUF		(1 << 15) /* host can merge RX bufs */
283 #define	VIRTIO_NET_F_STATUS		(1 << 16) /* cfg status field present */
284 #define	VIRTIO_F_RING_NOTIFY_ON_EMPTY	(1 << 24)
285 #define	VIRTIO_F_RING_INDIRECT_DESC	(1 << 28)
286 #define	VIRTIO_F_RING_EVENT_IDX		(1 << 29)
287 
288 struct viona_ring_params {
289 	uint64_t	vrp_pa;
290 	uint16_t	vrp_size;
291 	uint16_t	vrp_avail_idx;
292 	uint16_t	vrp_used_idx;
293 };
294 
295 void viona_ring_alloc(viona_link_t *, viona_vring_t *);
296 void viona_ring_free(viona_vring_t *);
297 int viona_ring_get_state(viona_link_t *, uint16_t, struct viona_ring_params *);
298 int viona_ring_set_state(viona_link_t *, uint16_t,
299     const struct viona_ring_params *);
300 int viona_ring_reset(viona_vring_t *, boolean_t);
301 int viona_ring_init(viona_link_t *, uint16_t, const struct viona_ring_params *);
302 boolean_t viona_ring_lease_renew(viona_vring_t *);
303 bool vring_need_bail(const viona_vring_t *);
304 int viona_ring_pause(viona_vring_t *);
305 
306 int vq_popchain(viona_vring_t *, struct iovec *, uint_t, uint16_t *,
307     vmm_page_t **);
308 void vq_pushchain(viona_vring_t *, uint32_t, uint16_t);
309 void vq_pushchain_many(viona_vring_t *, uint_t, used_elem_t *);
310 
311 void viona_intr_ring(viona_vring_t *ring, boolean_t);
312 void viona_ring_set_no_notify(viona_vring_t *, boolean_t);
313 void viona_ring_disable_notify(viona_vring_t *);
314 void viona_ring_enable_notify(viona_vring_t *);
315 uint16_t viona_ring_num_avail(viona_vring_t *);
316 
317 
318 void viona_rx_init(void);
319 void viona_rx_fini(void);
320 int viona_rx_set(viona_link_t *);
321 void viona_rx_clear(viona_link_t *);
322 void viona_worker_rx(viona_vring_t *, viona_link_t *);
323 
324 extern kmutex_t viona_force_copy_lock;
325 void viona_worker_tx(viona_vring_t *, viona_link_t *);
326 void viona_tx_ring_alloc(viona_vring_t *, const uint16_t);
327 void viona_tx_ring_free(viona_vring_t *, const uint16_t);
328 
329 void viona_neti_attach(void);
330 void viona_neti_detach(void);
331 viona_neti_t *viona_neti_lookup_by_zid(zoneid_t);
332 void viona_neti_rele(viona_neti_t *);
333 int viona_hook(viona_link_t *, viona_vring_t *, mblk_t **, boolean_t);
334 
335 #endif	/* _VIONA_IMPL_H */
336