Home | History | Annotate | Download | only in sys
      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 2006 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 			CPUSET_DEL(tmpset, pix);		\
    152 			if (CPUSET_ISNULL(tmpset))		\
    153 				break;				\
    154 		}						\
    155 	}							\
    156 	membar_stld();						\
    157 	send_mondo_set(xc_cpuset);				\
    158 }
    159 
    160 /*
    161  * set up and notify a x-call request, signalling xc_cpuset
    162  * cpus to enter xc_loop()
    163  */
    164 #define	SEND_MBOX_MONDO_XC_ENTER(xc_cpuset)			\
    165 {								\
    166 	int pix;						\
    167 	cpuset_t  tmpset = xc_cpuset;				\
    168 	for (pix = 0; pix < NCPU; pix++) {			\
    169 		if (CPU_IN_SET(tmpset, pix)) {			\
    170 			ASSERT(xc_mbox[pix].xc_state ==		\
    171 			    XC_IDLE);				\
    172 			xc_mbox[pix].xc_state = XC_ENTER;	\
    173 			CPUSET_DEL(tmpset, pix);		\
    174 			if (CPUSET_ISNULL(tmpset)) {		\
    175 				break;				\
    176 			}					\
    177 		}						\
    178 	}							\
    179 	send_mondo_set(xc_cpuset);				\
    180 }
    181 
    182 /*
    183  * wait x-call requests to be completed
    184  */
    185 #define	WAIT_MBOX_DONE(xc_cpuset, lcx, state, sync)			\
    186 {									\
    187 	int pix;							\
    188 	uint64_t loop_cnt = 0;						\
    189 	cpuset_t tmpset;						\
    190 	cpuset_t  recv_cpuset;						\
    191 	int first_time = 1;						\
    192 	CPUSET_ZERO(recv_cpuset);					\
    193 	while (!CPUSET_ISEQUAL(recv_cpuset, xc_cpuset)) {		\
    194 		tmpset = xc_cpuset;					\
    195 		for (pix = 0; pix < NCPU; pix++) {			\
    196 			if (CPU_IN_SET(tmpset, pix)) {			\
    197 				if (xc_mbox[pix].xc_state == state) {	\
    198 					CPUSET_ADD(recv_cpuset, pix);	\
    199 				}					\
    200 			}						\
    201 			CPUSET_DEL(tmpset, pix);			\
    202 			if (CPUSET_ISNULL(tmpset))			\
    203 				break;					\
    204 		}							\
    205 		if (loop_cnt++ > xc_func_time_limit) {			\
    206 			if (sendmondo_in_recover) {			\
    207 				drv_usecwait(1);			\
    208 				loop_cnt = 0;				\
    209 				continue;				\
    210 			}						\
    211 			_NOTE(CONSTANTCONDITION)			\
    212 			if (sync && first_time) {			\
    213 				XT_SYNC_SOME(xc_cpuset);		\
    214 				first_time = 0;				\
    215 				loop_cnt = 0;				\
    216 				continue;				\
    217 			}						\
    218 			panic("WAIT_MBOX_DONE() timeout, "		\
    219 				"recv_cpuset 0x%lx, xc cpuset 0x%lx ",	\
    220 				*(ulong_t *)&recv_cpuset,		\
    221 				*(ulong_t *)&xc_cpuset);		\
    222 		}							\
    223 	}								\
    224 }
    225 
    226 /*
    227  * xc_state flags
    228  */
    229 enum xc_states {
    230 	XC_IDLE = 0,	/* not in the xc_loop(); set by xc_loop */
    231 	XC_ENTER,	/* entering xc_loop(); set by xc_attention */
    232 	XC_WAIT,	/* entered xc_loop(); set by xc_loop */
    233 	XC_DOIT,	/* xcall request; set by xc_one, xc_some, or xc_all */
    234 	XC_EXIT		/* exiting xc_loop(); set by xc_dismissed */
    235 };
    236 
    237 /*
    238  * user provided handlers must be pc aligned
    239  */
    240 #define	PC_ALIGN 4
    241 
    242 #ifdef TRAPTRACE
    243 #define	XC_TRACE(type, cpus, func, arg1, arg2) \
    244 		xc_trace((type), (cpus), (func), (arg1), (arg2))
    245 #else /* !TRAPTRACE */
    246 #define	XC_TRACE(type, cpus, func, arg1, arg2)
    247 #endif /* TRAPTRACE */
    248 
    249 #if defined(DEBUG) || defined(TRAPTRACE)
    250 /*
    251  * get some statistics when xc/xt routines are called
    252  */
    253 
    254 #define	XC_STAT_INC(a)	(a)++;
    255 #define	XC_CPUID	0
    256 
    257 #define	XT_ONE_SELF	1
    258 #define	XT_ONE_OTHER	2
    259 #define	XT_SOME_SELF	3
    260 #define	XT_SOME_OTHER	4
    261 #define	XT_ALL_SELF	5
    262 #define	XT_ALL_OTHER	6
    263 #define	XC_ONE_SELF	7
    264 #define	XC_ONE_OTHER	8
    265 #define	XC_ONE_OTHER_H	9
    266 #define	XC_SOME_SELF	10
    267 #define	XC_SOME_OTHER	11
    268 #define	XC_SOME_OTHER_H	12
    269 #define	XC_ALL_SELF	13
    270 #define	XC_ALL_OTHER	14
    271 #define	XC_ALL_OTHER_H	15
    272 #define	XC_ATTENTION	16
    273 #define	XC_DISMISSED	17
    274 #define	XC_LOOP_ENTER	18
    275 #define	XC_LOOP_DOIT	19
    276 #define	XC_LOOP_EXIT	20
    277 
    278 extern	uint_t x_dstat[NCPU][XC_LOOP_EXIT+1];
    279 extern	uint_t x_rstat[NCPU][4];
    280 #define	XC_LOOP		1
    281 #define	XC_SERV		2
    282 
    283 #define	XC_STAT_INIT(cpuid) 				\
    284 {							\
    285 	x_dstat[cpuid][XC_CPUID] = 0xffffff00 | cpuid;	\
    286 	x_rstat[cpuid][XC_CPUID] = 0xffffff00 | cpuid;	\
    287 }
    288 
    289 #else /* DEBUG || TRAPTRACE */
    290 
    291 #define	XC_STAT_INIT(cpuid)
    292 #define	XC_STAT_INC(a)
    293 #define	XC_ATTENTION_CPUSET(x)
    294 #define	XC_DISMISSED_CPUSET(x)
    295 
    296 #endif /* DEBUG || TRAPTRACE */
    297 
    298 #endif	/* !_ASM */
    299 
    300 /*
    301  * Maximum delay in milliseconds to wait for send_mondo to complete
    302  */
    303 #define	XC_SEND_MONDO_MSEC	1000
    304 
    305 #ifdef	__cplusplus
    306 }
    307 #endif
    308 
    309 #endif	/* _SYS_XC_IMPL_H */
    310