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