1da14cebEric Cheng/*
2da14cebEric Cheng * CDDL HEADER START
3da14cebEric Cheng *
4da14cebEric Cheng * The contents of this file are subject to the terms of the
5da14cebEric Cheng * Common Development and Distribution License (the "License").
6da14cebEric Cheng * You may not use this file except in compliance with the License.
7da14cebEric Cheng *
8da14cebEric Cheng * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da14cebEric Cheng * or http://www.opensolaris.org/os/licensing.
10da14cebEric Cheng * See the License for the specific language governing permissions
11da14cebEric Cheng * and limitations under the License.
12da14cebEric Cheng *
13da14cebEric Cheng * When distributing Covered Code, include this CDDL HEADER in each
14da14cebEric Cheng * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da14cebEric Cheng * If applicable, add the following below this CDDL HEADER, with the
16da14cebEric Cheng * fields enclosed by brackets "[]" replaced with your own identifying
17da14cebEric Cheng * information: Portions Copyright [yyyy] [name of copyright owner]
18da14cebEric Cheng *
19da14cebEric Cheng * CDDL HEADER END
20da14cebEric Cheng */
21da14cebEric Cheng
22da14cebEric Cheng/*
230dc2366Venugopal Iyer * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24da14cebEric Cheng * Use is subject to license terms.
255647635Ryan Zezeski * Copyright 2017 Joyent, Inc.
26da14cebEric Cheng */
27da14cebEric Cheng
28da14cebEric Cheng#ifndef	_SYS_MAC_SOFT_RING_H
29da14cebEric Cheng#define	_SYS_MAC_SOFT_RING_H
30da14cebEric Cheng
31da14cebEric Cheng#ifdef	__cplusplus
32da14cebEric Chengextern "C" {
33da14cebEric Cheng#endif
34da14cebEric Cheng
35da14cebEric Cheng#include <sys/types.h>
36da14cebEric Cheng#include <sys/cpuvar.h>
370dc2366Venugopal Iyer#include <sys/cpupart.h>
38da14cebEric Cheng#include <sys/processor.h>
39da14cebEric Cheng#include <sys/stream.h>
40da14cebEric Cheng#include <sys/squeue.h>
41da14cebEric Cheng#include <sys/dlpi.h>
42da14cebEric Cheng#include <sys/mac_impl.h>
430dc2366Venugopal Iyer#include <sys/mac_stat.h>
44da14cebEric Cheng
45da14cebEric Cheng#define	S_RING_NAMELEN 64
46da14cebEric Cheng
472b24ab6Sebastien Roy#define	MAX_SR_FANOUT	24
48da14cebEric Cheng
49da14cebEric Chengextern boolean_t mac_soft_ring_enable;
50da14cebEric Chengextern boolean_t mac_latency_optimize;
51da14cebEric Cheng
52da14cebEric Chengtypedef struct mac_soft_ring_s mac_soft_ring_t;
53da14cebEric Chengtypedef struct mac_soft_ring_set_s mac_soft_ring_set_t;
54da14cebEric Cheng
55da14cebEric Chengtypedef void (*mac_soft_ring_drain_func_t)(mac_soft_ring_t *);
56da14cebEric Chengtypedef mac_tx_cookie_t (*mac_tx_func_t)(mac_soft_ring_set_t *, mblk_t *,
57da14cebEric Cheng    uintptr_t, uint16_t, mblk_t **);
58da14cebEric Cheng
59da14cebEric Cheng
60da14cebEric Cheng/* Tx notify callback */
61da14cebEric Chengtypedef struct mac_tx_notify_cb_s {
62da14cebEric Cheng	mac_cb_t		mtnf_link;	/* Linked list of callbacks */
63da14cebEric Cheng	mac_tx_notify_t		mtnf_fn;	/* The callback function */
64da14cebEric Cheng	void			*mtnf_arg;	/* Callback function argument */
65da14cebEric Cheng} mac_tx_notify_cb_t;
66da14cebEric Cheng
67da14cebEric Chengstruct mac_soft_ring_s {
68da14cebEric Cheng	/* Keep the most used members 64bytes cache aligned */
69da14cebEric Cheng	kmutex_t	s_ring_lock;	/* lock before using any member */
70da14cebEric Cheng	uint16_t	s_ring_type;	/* processing model of the sq */
71da14cebEric Cheng	uint16_t	s_ring_state;	/* state flags and message count */
72da14cebEric Cheng	int		s_ring_count;	/* # of mblocks in mac_soft_ring */
73da14cebEric Cheng	size_t		s_ring_size;	/* Size of data queued */
74da14cebEric Cheng	mblk_t		*s_ring_first;	/* first mblk chain or NULL */
75da14cebEric Cheng	mblk_t		*s_ring_last;	/* last mblk chain or NULL */
76da14cebEric Cheng
77da14cebEric Cheng	mac_direct_rx_t	s_ring_rx_func;
78da14cebEric Cheng	void		*s_ring_rx_arg1;
79da14cebEric Cheng	mac_resource_handle_t  s_ring_rx_arg2;
80da14cebEric Cheng
81da14cebEric Cheng	/*
82da14cebEric Cheng	 * Threshold after which packets get dropped.
83da14cebEric Cheng	 * Is always greater than s_ring_tx_hiwat
84da14cebEric Cheng	 */
85da14cebEric Cheng	int		s_ring_tx_max_q_cnt;
86da14cebEric Cheng	/* # of mblocks after which to apply flow control */
87da14cebEric Cheng	int		s_ring_tx_hiwat;
88da14cebEric Cheng	/* # of mblocks after which to relieve flow control */
89da14cebEric Cheng	int		s_ring_tx_lowat;
90da14cebEric Cheng	boolean_t	s_ring_tx_woken_up;
91da14cebEric Cheng	uint32_t	s_ring_hiwat_cnt;	/* times blocked for Tx descs */
92da14cebEric Cheng
93da14cebEric Cheng	void		*s_ring_tx_arg1;
94da14cebEric Cheng	void		*s_ring_tx_arg2;
95da14cebEric Cheng
96da14cebEric Cheng	/* Tx notify callback */
97da14cebEric Cheng	mac_cb_info_t	s_ring_notify_cb_info;		/* cb list info */
98da14cebEric Cheng	mac_cb_t	*s_ring_notify_cb_list;		/* The cb list */
99da14cebEric Cheng
100da14cebEric Cheng	clock_t		s_ring_awaken;	/* time async thread was awakened */
101da14cebEric Cheng
102da14cebEric Cheng	kthread_t	*s_ring_run;	/* Current thread processing sq */
103da14cebEric Cheng	processorid_t	s_ring_cpuid;	/* processor to bind to */
104da14cebEric Cheng	processorid_t	s_ring_cpuid_save;	/* saved cpuid during offline */
105da14cebEric Cheng	kcondvar_t	s_ring_async;	/* async thread blocks on */
106da14cebEric Cheng	clock_t		s_ring_wait;	/* lbolts to wait after a fill() */
107da14cebEric Cheng	timeout_id_t	s_ring_tid;	/* timer id of pending timeout() */
108da14cebEric Cheng	kthread_t	*s_ring_worker;	/* kernel thread id */
109da14cebEric Cheng	char		s_ring_name[S_RING_NAMELEN + 1];
110da14cebEric Cheng	uint32_t	s_ring_total_inpkt;
1110dc2366Venugopal Iyer	uint32_t	s_ring_total_rbytes;
112da14cebEric Cheng	uint32_t	s_ring_drops;
113da14cebEric Cheng	struct mac_client_impl_s *s_ring_mcip;
114da14cebEric Cheng	kstat_t		*s_ring_ksp;
115da14cebEric Cheng
116da14cebEric Cheng	/* Teardown, poll disable control ops */
117da14cebEric Cheng	kcondvar_t	s_ring_client_cv; /* Client wait for control op */
118da14cebEric Cheng
119da14cebEric Cheng	mac_soft_ring_set_t *s_ring_set;   /* The SRS this ring belongs to */
120da14cebEric Cheng	mac_soft_ring_t	*s_ring_next;
121da14cebEric Cheng	mac_soft_ring_t	*s_ring_prev;
122da14cebEric Cheng	mac_soft_ring_drain_func_t s_ring_drain_func;
1230dc2366Venugopal Iyer
1240dc2366Venugopal Iyer	mac_tx_stats_t	s_st_stat;
125da14cebEric Cheng};
126da14cebEric Cheng
127da14cebEric Chengtypedef void (*mac_srs_drain_proc_t)(mac_soft_ring_set_t *, uint_t);
128da14cebEric Cheng
129da14cebEric Cheng/* Transmit side Soft Ring Set */
130da14cebEric Chengtypedef struct mac_srs_tx_s {
131da14cebEric Cheng	/* Members for Tx size processing */
132da14cebEric Cheng	uint32_t	st_mode;
133da14cebEric Cheng	mac_tx_func_t	st_func;
134da14cebEric Cheng	void		*st_arg1;
135da14cebEric Cheng	void		*st_arg2;
136da14cebEric Cheng	mac_group_t	*st_group;	/* TX group for share */
137da14cebEric Cheng	boolean_t	st_woken_up;
138da14cebEric Cheng
139da14cebEric Cheng	/*
140da14cebEric Cheng	 * st_max_q_cnt is the queue depth threshold to limit
141da14cebEric Cheng	 * outstanding packets on the Tx SRS. Once the limit
142da14cebEric Cheng	 * is reached, Tx SRS will drop packets until the
143da14cebEric Cheng	 * limit goes below the threshold.
144da14cebEric Cheng	 */
145da14cebEric Cheng	uint32_t	st_max_q_cnt;	/* max. outstanding packets */
146da14cebEric Cheng	/*
147da14cebEric Cheng	 * st_hiwat is used Tx serializer and bandwidth mode.
148da14cebEric Cheng	 * This is the queue depth threshold upto which
149da14cebEric Cheng	 * packets will get buffered with no flow-control
150da14cebEric Cheng	 * back pressure applied to the caller. Once this
151da14cebEric Cheng	 * threshold is reached, back pressure will be
152da14cebEric Cheng	 * applied to the caller of mac_tx() (mac_tx() starts
153da14cebEric Cheng	 * returning a cookie to indicate a blocked SRS).
154da14cebEric Cheng	 * st_hiwat should always be lesser than or equal to
155da14cebEric Cheng	 * st_max_q_cnt.
156da14cebEric Cheng	 */
157da14cebEric Cheng	uint32_t	st_hiwat;	/* mblk cnt to apply flow control */
158da14cebEric Cheng	uint32_t	st_lowat;	/* mblk cnt to relieve flow control */
1590dc2366Venugopal Iyer	uint32_t	st_hiwat_cnt; /* times blocked for Tx descs */
1600dc2366Venugopal Iyer	mac_tx_stats_t	st_stat;
1610dc2366Venugopal Iyer	mac_capab_aggr_t	st_capab_aggr;
162da14cebEric Cheng	/*
1630dc2366Venugopal Iyer	 * st_soft_rings is used as an array to store aggr Tx soft
1640dc2366Venugopal Iyer	 * rings. When aggr_find_tx_ring() returns a pseudo ring,
1650dc2366Venugopal Iyer	 * the associated soft ring has to be found. st_soft_rings
1660dc2366Venugopal Iyer	 * array stores the soft ring associated with a pseudo Tx
1670dc2366Venugopal Iyer	 * ring and it can be accessed using the pseudo ring
1680dc2366Venugopal Iyer	 * index (mr_index). Note that the ring index is unique
1690dc2366Venugopal Iyer	 * for each ring in a group.
170da14cebEric Cheng	 */
1710dc2366Venugopal Iyer	mac_soft_ring_t **st_soft_rings;
172da14cebEric Cheng} mac_srs_tx_t;
173da14cebEric Cheng
174da14cebEric Cheng/* Receive side Soft Ring Set */
175da14cebEric Chengtypedef struct mac_srs_rx_s {
176da14cebEric Cheng	/*
177da14cebEric Cheng	 * Upcall Function for fanout, Rx processing etc. Perhaps
178da14cebEric Cheng	 * the same 3 members below can be used for Tx
179da14cebEric Cheng	 * processing, but looking around, mac_rx_func_t has
180da14cebEric Cheng	 * proliferated too much into various files at different
181da14cebEric Cheng	 * places. I am leaving the consolidation battle for
182da14cebEric Cheng	 * another day.
183da14cebEric Cheng	 */
184da14cebEric Cheng	mac_direct_rx_t		sr_func;	/* srs_lock */
185da14cebEric Cheng	void			*sr_arg1;	/* srs_lock */
1867ec6bfcToomas Soome	mac_resource_handle_t	sr_arg2;	/* srs_lock */
187da14cebEric Cheng	mac_rx_func_t		sr_lower_proc;	/* Atomically changed */
188da14cebEric Cheng	uint32_t		sr_poll_pkt_cnt;
189da14cebEric Cheng	uint32_t		sr_poll_thres;
190da14cebEric Cheng
191da14cebEric Cheng	/* mblk cnt to apply flow control */
192da14cebEric Cheng	uint32_t		sr_hiwat;
193da14cebEric Cheng	/* mblk cnt to relieve flow control */
194da14cebEric Cheng	uint32_t		sr_lowat;
1950dc2366Venugopal Iyer	mac_rx_stats_t		sr_stat;
196da14cebEric Cheng
197da14cebEric Cheng	/* Times polling was enabled */
198da14cebEric Cheng	uint32_t		sr_poll_on;
199da14cebEric Cheng	/* Times polling was enabled by worker thread */
200da14cebEric Cheng	uint32_t		sr_worker_poll_on;
201da14cebEric Cheng	/* Times polling was disabled */
202da14cebEric Cheng	uint32_t		sr_poll_off;
203da14cebEric Cheng	/* Poll thread signalled count */
204da14cebEric Cheng	uint32_t		sr_poll_thr_sig;
205da14cebEric Cheng	/* Poll thread busy */
206da14cebEric Cheng	uint32_t		sr_poll_thr_busy;
207da14cebEric Cheng	/* SRS drains, stays in poll mode but doesn't poll */
208da14cebEric Cheng	uint32_t		sr_poll_drain_no_poll;
209da14cebEric Cheng	/*
210da14cebEric Cheng	 * SRS has nothing to do and no packets in H/W but
211da14cebEric Cheng	 * there is a backlog in softrings. SRS stays in
212da14cebEric Cheng	 * poll mode but doesn't do polling.
213da14cebEric Cheng	 */
214da14cebEric Cheng	uint32_t		sr_poll_no_poll;
215da14cebEric Cheng	/* Active polling restarted */
216da14cebEric Cheng	uint32_t		sr_below_hiwat;
217da14cebEric Cheng	/* Found packets in last poll so try and poll again */
218da14cebEric Cheng	uint32_t		sr_poll_again;
219da14cebEric Cheng	/*
220da14cebEric Cheng	 * Packets in queue but poll thread not allowed to process so
221da14cebEric Cheng	 * signal the worker thread.
222da14cebEric Cheng	 */
223da14cebEric Cheng	uint32_t		sr_poll_sig_worker;
224da14cebEric Cheng	/*
225da14cebEric Cheng	 * Poll thread has nothing to do and H/W has nothing so
226da14cebEric Cheng	 * reenable the interrupts.
227da14cebEric Cheng	 */
228da14cebEric Cheng	uint32_t		sr_poll_intr_enable;
229da14cebEric Cheng	/*
230da14cebEric Cheng	 * Poll thread has nothing to do and worker thread was already
231da14cebEric Cheng	 * running so it can decide to reenable interrupt or poll again.
232da14cebEric Cheng	 */
233da14cebEric Cheng	uint32_t		sr_poll_goto_sleep;
234da14cebEric Cheng	/* Worker thread goes back to draining the queue */
235da14cebEric Cheng	uint32_t		sr_drain_again;
2368ac2989Eric Cheng	/* More Packets in queue so signal the poll thread to drain */
237ae6aa22Venugopal Iyer	uint32_t		sr_drain_poll_sig;
2388ac2989Eric Cheng	/* More Packets in queue so signal the worker thread to drain */
2398ac2989Eric Cheng	uint32_t		sr_drain_worker_sig;
240da14cebEric Cheng	/* Poll thread is already running so worker has nothing to do */
241da14cebEric Cheng	uint32_t		sr_drain_poll_running;
242da14cebEric Cheng	/* We have packets already queued so keep polling */
243da14cebEric Cheng	uint32_t		sr_drain_keep_polling;
244da14cebEric Cheng	/* Drain is done and interrupts are reenabled */
245da14cebEric Cheng	uint32_t		sr_drain_finish_intr;
246da14cebEric Cheng	/* Polling thread needs to schedule worker wakeup */
247da14cebEric Cheng	uint32_t		sr_poll_worker_wakeup;
248da14cebEric Cheng} mac_srs_rx_t;
249da14cebEric Cheng
250da14cebEric Cheng/*
251da14cebEric Cheng * mac_soft_ring_set_s:
252da14cebEric Cheng * This is used both for Tx and Rx side. The srs_type identifies Rx or
253da14cebEric Cheng * Tx type.
254da14cebEric Cheng *
255da14cebEric Cheng * Note that the structure is carefully crafted, with Rx elements coming
256da14cebEric Cheng * first followed by Tx specific members. Future additions to this
257da14cebEric Cheng * structure should follow the same guidelines.
258da14cebEric Cheng *
259da14cebEric Cheng * Rx-side notes:
260da14cebEric Cheng * mac_rx_classify_flow_add() always creates a mac_soft_ring_set_t and fn_flow
261da14cebEric Cheng * points to info from it (func = srs_lower_proc, arg = soft_ring_set). On
262da14cebEric Cheng * interrupt path, srs_lower_proc does B/W adjustment and switch to polling mode
263da14cebEric Cheng * (if poll capable) and feeds the packets to soft_ring_list via choosen
264da14cebEric Cheng * fanout type (specified by srs_type). In poll mode, the poll thread which is
265da14cebEric Cheng * also a pointer can pick up the packets and feed them to various
266da14cebEric Cheng * soft_ring_list.
267da14cebEric Cheng *
268da14cebEric Cheng * The srs_type can either be protocol based or fanout based where fanout itelf
269da14cebEric Cheng * can be various types
270da14cebEric Cheng *
271da14cebEric Cheng * The polling works by turning off interrupts as soon as a packets
272da14cebEric Cheng * are queued on the soft ring set. Once the backlog is clear and poll
273da14cebEric Cheng * thread return empty handed i.e. Rx ring doesn't have anything, the
274da14cebEric Cheng * interrupt is turned back on. For this purpose we keep a separate
275da14cebEric Cheng * srs_poll_pkt_cnt counter which tracks the packets queued between SRS
276da14cebEric Cheng * and the soft rings as well. The counter is incremented when packets
277da14cebEric Cheng * are queued and decremented when SRS processes them (in case it has
278da14cebEric Cheng * no soft rings) or the soft ring process them. Its important that
279da14cebEric Cheng * in case SRS has softrings, the decrement doesn't happen till the
280da14cebEric Cheng * packet is processed by the soft rings since it takes very little time
281da14cebEric Cheng * for SRS to queue packet from SRS to soft rings and it will keep
282da14cebEric Cheng * bringing more packets in the system faster than soft rings can
283da14cebEric Cheng * process them.
284da14cebEric Cheng *
285da14cebEric Cheng * Tx side notes:
286da14cebEric Cheng * The srs structure acts as a serializer with a worker thread. The
287da14cebEric Cheng * default behavior of srs though is to act as a pass-thru. The queues
288da14cebEric Cheng * (srs_first, srs_last, srs_count) get used when Tx ring runs out of Tx
289da14cebEric Cheng * descriptors or to enforce bandwidth limits.
290da14cebEric Cheng *
291da14cebEric Cheng * When multiple Tx rings are present, the SRS state will be set to
292da14cebEric Cheng * SRS_FANOUT_OTH. Outgoing packets coming into mac_tx_srs_process()
293da14cebEric Cheng * function will be fanned out to one of the Tx side soft rings based on
294da14cebEric Cheng * a hint passed in mac_tx_srs_process(). Each soft ring, in turn, will
295da14cebEric Cheng * be associated with a distinct h/w Tx ring.
296da14cebEric Cheng */
297da14cebEric Cheng
298da14cebEric Chengstruct mac_soft_ring_set_s {
299da14cebEric Cheng	/*
300da14cebEric Cheng	 * Common elements, common to both Rx and Tx SRS type.
301da14cebEric Cheng	 * The following block of fields are protected by srs_lock
302da14cebEric Cheng	 */
303da14cebEric Cheng	kmutex_t	srs_lock;
304da14cebEric Cheng	uint32_t	srs_type;
305da14cebEric Cheng	uint32_t	srs_state;	/* state flags */
306da14cebEric Cheng	uint32_t	srs_count;
307da14cebEric Cheng	mblk_t		*srs_first;	/* first mblk chain or NULL */
308da14cebEric Cheng	mblk_t		*srs_last;	/* last mblk chain or NULL */
309da14cebEric Cheng	kcondvar_t	srs_async;	/* cv for worker thread */
310da14cebEric Cheng	kcondvar_t	srs_cv;		/* cv for poll thread */
311da14cebEric Cheng	kcondvar_t	srs_quiesce_done_cv;	/* cv for removal */
312da14cebEric Cheng	timeout_id_t	srs_tid;	/* timeout id for pending timeout */
313da14cebEric Cheng
314da14cebEric Cheng	/*
315da14cebEric Cheng	 * List of soft rings & processing function.
316da14cebEric Cheng	 * The following block is protected by Rx quiescence.
317da14cebEric Cheng	 * i.e. they can be changed only after quiescing the SRS
318da14cebEric Cheng	 * Protected by srs_lock.
319da14cebEric Cheng	 */
320da14cebEric Cheng	mac_soft_ring_t	*srs_soft_ring_head;
321da14cebEric Cheng	mac_soft_ring_t	*srs_soft_ring_tail;