xref: /illumos-gate/usr/src/uts/sun4/sys/xc_impl.h (revision 7c478bd9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #ifndef	_SYS_XC_IMPL_H
28 #define	_SYS_XC_IMPL_H
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #ifdef	__cplusplus
33 extern "C" {
34 #endif
35 
36 #ifndef _ASM
37 
38 #include <sys/note.h>
39 #include <sys/cpu_module.h>
40 #include <sys/panic.h>		/* for panic_quiesce */
41 
42 extern cpuset_t cpu_ready_set;	/* cpus ready for x-call */
43 extern void send_self_xcall(struct cpu *, uint64_t, uint64_t, xcfunc_t *);
44 extern uint_t xc_loop(void);
45 extern uint_t xc_serv(void);
46 extern void xc_stop(struct regs *);
47 #ifdef TRAPTRACE
48 extern void xc_trace(uint_t, cpuset_t *, xcfunc_t *, uint64_t, uint64_t);
49 #endif /* TRAPTRACE */
50 extern uint64_t xc_func_time_limit;
51 
52 extern uint_t sendmondo_in_recover;
53 
54 /*
55  * Lightweight XTrap Sync
56  */
57 #ifdef sun4v
58 #define	XT_SYNC_ONE(cpuid)				\
59 {							\
60 	cpuset_t set;					\
61 	CPUSET_ONLY(set, cpuid);			\
62 	xt_sync(set);					\
63 }
64 
65 #define	XT_SYNC_SOME(cpuset)				\
66 {							\
67 	xt_sync(cpuset);				\
68 }
69 
70 #else /* sun4v */
71 
72 #define	XT_SYNC_ONE(cpuid)				\
73 {							\
74 	init_mondo((xcfunc_t *)xt_sync_tl1, 0, 0);	\
75 	send_one_mondo(cpuid);				\
76 }
77 
78 #define	XT_SYNC_SOME(cpuset)				\
79 {							\
80 	init_mondo((xcfunc_t *)xt_sync_tl1, 0, 0);	\
81 	send_mondo_set(cpuset);				\
82 }
83 
84 #endif /* sun4v */
85 
86 /*
87  * Protect the dispatching of the mondo vector
88  */
89 
90 #define	XC_SPL_ENTER(cpuid, opl)					\
91 {									\
92 	opl = splr(XCALL_PIL);						\
93 	cpuid = CPU->cpu_id;						\
94 	if (xc_spl_enter[cpuid] && !panic_quiesce)			\
95 		cmn_err(CE_PANIC, "XC SPL ENTER already entered (0x%x)",\
96 		cpuid);							\
97 	xc_spl_enter[cpuid] = 1;					\
98 }
99 
100 #define	XC_SPL_EXIT(cpuid, opl)				\
101 {							\
102 	ASSERT(xc_spl_enter[cpuid] != 0);		\
103 	xc_spl_enter[cpuid] = 0;			\
104 	splx(opl);					\
105 }
106 
107 /*
108  * set up a x-call request
109  */
110 #define	XC_SETUP(cpuid, func, arg1, arg2)		\
111 {							\
112 	xc_mbox[cpuid].xc_func = func;			\
113 	xc_mbox[cpuid].xc_arg1 = arg1;			\
114 	xc_mbox[cpuid].xc_arg2 = arg2;			\
115 	xc_mbox[cpuid].xc_state = XC_DOIT;		\
116 }
117 
118 /*
119  * set up x-call requests to the cpuset
120  */
121 #define	SEND_MBOX_ONLY(xc_cpuset, func, arg1, arg2, lcx, state)		\
122 {									\
123 	int pix;							\
124 	cpuset_t  tmpset = xc_cpuset;					\
125 	for (pix = 0; pix < NCPU; pix++) {				\
126 		if (CPU_IN_SET(tmpset, pix)) {				\
127 			ASSERT(MUTEX_HELD(&xc_sys_mutex));		\
128 			ASSERT(CPU_IN_SET(xc_mbox[lcx].xc_cpuset, pix));\
129 			ASSERT(xc_mbox[pix].xc_state == state);		\
130 			XC_SETUP(pix, func, arg1, arg2);		\
131 			membar_stld();					\
132 			CPUSET_DEL(tmpset, pix);			\
133 			CPU_STATS_ADDQ(CPU, sys, xcalls, 1);		\
134 			if (CPUSET_ISNULL(tmpset))			\
135 				break;					\
136 		}							\
137 	}								\
138 }
139 
140 /*
141  * set up and notify a x-call request to the cpuset
142  */
143 #define	SEND_MBOX_MONDO(xc_cpuset, func, arg1, arg2, state)	\
144 {								\
145 	int pix;						\
146 	cpuset_t  tmpset = xc_cpuset;				\
147 	for (pix = 0; pix < NCPU; pix++) {			\
148 		if (CPU_IN_SET(tmpset, pix)) {			\
149 			ASSERT(xc_mbox[pix].xc_state == state);	\
150 			XC_SETUP(pix, func, arg1, arg2);	\
151 			membar_stld();				\
152 			send_one_mondo(pix);			\
153 			CPUSET_DEL(tmpset, pix);		\
154 			if (CPUSET_ISNULL(tmpset))		\
155 				break;				\
156 		}						\
157 	}							\
158 }
159 
160 /*
161  * wait x-call requests to be completed
162  */
163 #define	WAIT_MBOX_DONE(xc_cpuset, lcx, state, sync)			\
164 {									\
165 	int pix;							\
166 	uint64_t loop_cnt = 0;						\
167 	cpuset_t tmpset;						\
168 	cpuset_t  recv_cpuset;						\
169 	int first_time = 1;						\
170 	CPUSET_ZERO(recv_cpuset);					\
171 	while (!CPUSET_ISEQUAL(recv_cpuset, xc_cpuset)) {		\
172 		tmpset = xc_cpuset;					\
173 		for (pix = 0; pix < NCPU; pix++) {			\
174 			if (CPU_IN_SET(tmpset, pix)) {			\
175 				if (xc_mbox[pix].xc_state == state) {	\
176 					CPUSET_ADD(recv_cpuset, pix);	\
177 				}					\
178 			}						\
179 			CPUSET_DEL(tmpset, pix);			\
180 			if (CPUSET_ISNULL(tmpset))			\
181 				break;					\
182 		}							\
183 		if (loop_cnt++ > xc_func_time_limit) {			\
184 			if (sendmondo_in_recover) {			\
185 				drv_usecwait(1);			\
186 				loop_cnt = 0;				\
187 				continue;				\
188 			}						\
189 			_NOTE(CONSTANTCONDITION)			\
190 			if (sync && first_time) {			\
191 				XT_SYNC_SOME(xc_cpuset);		\
192 				first_time = 0;				\
193 				loop_cnt = 0;				\
194 				continue;				\
195 			}						\
196 			panic("WAIT_MBOX_DONE() timeout, "		\
197 				"recv_cpuset 0x%lx, xc cpuset 0x%lx ",	\
198 				recv_cpuset, xc_cpuset);		\
199 		}							\
200 	}								\
201 }
202 
203 /*
204  * xc_state flags
205  */
206 enum xc_states {
207 	XC_IDLE = 0,	/* not in the xc_loop(); set by xc_loop */
208 	XC_ENTER,	/* entering xc_loop(); set by xc_attention */
209 	XC_WAIT,	/* entered xc_loop(); set by xc_loop */
210 	XC_DOIT,	/* xcall request; set by xc_one, xc_some, or xc_all */
211 	XC_EXIT		/* exiting xc_loop(); set by xc_dismissed */
212 };
213 
214 /*
215  * user provided handlers must be pc aligned
216  */
217 #define	PC_ALIGN 4
218 
219 #ifdef TRAPTRACE
220 #define	XC_TRACE(type, cpus, func, arg1, arg2) \
221 		xc_trace((type), (cpus), (func), (arg1), (arg2))
222 #else /* !TRAPTRACE */
223 #define	XC_TRACE(type, cpus, func, arg1, arg2)
224 #endif /* TRAPTRACE */
225 
226 #ifdef DEBUG
227 /*
228  * get some statistics when xc/xt routines are called
229  */
230 
231 #define	XC_STAT_INC(a)	(a)++;
232 #define	XC_CPUID	0
233 
234 #define	XT_ONE_SELF	1
235 #define	XT_ONE_OTHER	2
236 #define	XT_SOME_SELF	3
237 #define	XT_SOME_OTHER	4
238 #define	XT_ALL_SELF	5
239 #define	XT_ALL_OTHER	6
240 #define	XC_ONE_SELF	7
241 #define	XC_ONE_OTHER	8
242 #define	XC_ONE_OTHER_H	9
243 #define	XC_SOME_SELF	10
244 #define	XC_SOME_OTHER	11
245 #define	XC_SOME_OTHER_H	12
246 #define	XC_ALL_SELF	13
247 #define	XC_ALL_OTHER	14
248 #define	XC_ALL_OTHER_H	15
249 #define	XC_ATTENTION	16
250 #define	XC_DISMISSED	17
251 #define	XC_LOOP_ENTER	18
252 #define	XC_LOOP_DOIT	19
253 #define	XC_LOOP_EXIT	20
254 
255 extern	uint_t x_dstat[NCPU][XC_LOOP_EXIT+1];
256 extern	uint_t x_rstat[NCPU][4];
257 #define	XC_LOOP		1
258 #define	XC_SERV		2
259 
260 #define	XC_STAT_INIT(cpuid) 				\
261 {							\
262 	x_dstat[cpuid][XC_CPUID] = 0xffffff00 | cpuid;	\
263 	x_rstat[cpuid][XC_CPUID] = 0xffffff00 | cpuid;	\
264 }
265 
266 #else /* DEBUG */
267 
268 #define	XC_STAT_INIT(cpuid)
269 #define	XC_STAT_INC(a)
270 #define	XC_ATTENTION_CPUSET(x)
271 #define	XC_DISMISSED_CPUSET(x)
272 
273 #endif /* DEBUG */
274 
275 #endif	/* !_ASM */
276 
277 /*
278  * Maximum delay in milliseconds to wait for send_mondo to complete
279  */
280 #define	XC_SEND_MONDO_MSEC	1000
281 
282 #ifdef	__cplusplus
283 }
284 #endif
285 
286 #endif	/* _SYS_XC_IMPL_H */
287