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 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/systm.h> 29 #include <sys/cyclic.h> 30 #include <sys/cyclic_impl.h> 31 #include <sys/spl.h> 32 #include <sys/x_call.h> 33 #include <sys/kmem.h> 34 #include <sys/machsystm.h> 35 #include <sys/smp_impldefs.h> 36 #include <sys/psm_types.h> 37 #include <sys/atomic.h> 38 #include <sys/clock.h> 39 #include <sys/ddi_impldefs.h> 40 #include <sys/ddi_intr.h> 41 #include <sys/avintr.h> 42 43 static int cbe_vector; 44 static int cbe_ticks = 0; 45 46 static cyc_func_t volatile cbe_xcall_func; 47 static cpu_t *volatile cbe_xcall_cpu; 48 static void *cbe_xcall_farg; 49 static cpuset_t cbe_enabled; 50 51 static ddi_softint_hdl_impl_t cbe_low_hdl = 52 {0, NULL, NULL, NULL, 0, NULL, NULL, NULL}; 53 static ddi_softint_hdl_impl_t cbe_clock_hdl = 54 {0, NULL, NULL, NULL, 0, NULL, NULL, NULL}; 55 56 cyclic_id_t cbe_hres_cyclic; 57 int cbe_psm_timer_mode = TIMER_ONESHOT; 58 59 void cbe_hres_tick(void); 60 61 int 62 cbe_softclock(void) 63 { 64 cyclic_softint(CPU, CY_LOCK_LEVEL); 65 return (1); 66 } 67 68 int 69 cbe_low_level(void) 70 { 71 cpu_t *cpu = CPU; 72 73 cyclic_softint(cpu, CY_LOW_LEVEL); 74 return (1); 75 } 76 77 /* 78 * We can be in cbe_fire() either due to a cyclic-induced cross call, or due 79 * to the timer firing at level-14. Because cyclic_fire() can tolerate 80 * spurious calls, it would not matter if we called cyclic_fire() in both 81 * cases. 82 * 83 */ 84 int 85 cbe_fire(void) 86 { 87 cpu_t *cpu = CPU; 88 processorid_t me = cpu->cpu_id, i; 89 int cross_call = (cbe_xcall_func != NULL && cbe_xcall_cpu == cpu); 90 91 cyclic_fire(cpu); 92 93 if (cbe_psm_timer_mode != TIMER_ONESHOT && me == 0 && !cross_call) { 94 for (i = 1; i < NCPU; i++) { 95 if (CPU_IN_SET(cbe_enabled, i)) 96 send_dirint(i, CBE_HIGH_PIL); 97 } 98 } 99 100 if (cross_call) { 101 ASSERT(cbe_xcall_func != NULL && cbe_xcall_cpu == cpu); 102 (*cbe_xcall_func)(cbe_xcall_farg); 103 cbe_xcall_func = NULL; 104 cbe_xcall_cpu = NULL; 105 } 106 107 return (1); 108 } 109 110 /*ARGSUSED*/ 111 void 112 cbe_softint(void *arg, cyc_level_t level) 113 { 114 switch (level) { 115 case CY_LOW_LEVEL: 116 (*setsoftint)(CBE_LOW_PIL, cbe_low_hdl.ih_pending); 117 break; 118 case CY_LOCK_LEVEL: 119 (*setsoftint)(CBE_LOCK_PIL, cbe_clock_hdl.ih_pending); 120 break; 121 default: 122 panic("cbe_softint: unexpected soft level %d", level); 123 } 124 } 125 126 /*ARGSUSED*/ 127 void 128 cbe_reprogram(void *arg, hrtime_t time) 129 { 130 if (cbe_psm_timer_mode == TIMER_ONESHOT) 131 (*psm_timer_reprogram)(time); 132 } 133 134 /*ARGSUSED*/ 135 cyc_cookie_t 136 cbe_set_level(void *arg, cyc_level_t level) 137 { 138 int ipl; 139 140 switch (level) { 141 case CY_LOW_LEVEL: 142 ipl = CBE_LOW_PIL; 143 break; 144 case CY_LOCK_LEVEL: 145 ipl = CBE_LOCK_PIL; 146 break; 147 case CY_HIGH_LEVEL: 148 ipl = CBE_HIGH_PIL; 149 break; 150 default: 151 panic("cbe_set_level: unexpected level %d", level); 152 } 153 154 return (splr(ipltospl(ipl))); 155 } 156 157 /*ARGSUSED*/ 158 void 159 cbe_restore_level(void *arg, cyc_cookie_t cookie) 160 { 161 splx(cookie); 162 } 163 164 /*ARGSUSED*/ 165 void 166 cbe_xcall(void *arg, cpu_t *dest, cyc_func_t func, void *farg) 167 { 168 kpreempt_disable(); 169 170 if (dest == CPU) { 171 (*func)(farg); 172 kpreempt_enable(); 173 return; 174 } 175 176 ASSERT(cbe_xcall_func == NULL); 177 178 cbe_xcall_farg = farg; 179 membar_producer(); 180 cbe_xcall_cpu = dest; 181 cbe_xcall_func = func; 182 183 send_dirint(dest->cpu_id, CBE_HIGH_PIL); 184 185 while (cbe_xcall_func != NULL || cbe_xcall_cpu != NULL) 186 continue; 187 188 kpreempt_enable(); 189 190 ASSERT(cbe_xcall_func == NULL && cbe_xcall_cpu == NULL); 191 } 192 193 void * 194 cbe_configure(cpu_t *cpu) 195 { 196 return (cpu); 197 } 198 199 void 200 cbe_enable(void *arg) 201 { 202 processorid_t me = ((cpu_t *)arg)->cpu_id; 203 204 if ((cbe_psm_timer_mode != TIMER_ONESHOT) && (me == 0)) 205 return; 206 207 ASSERT(!CPU_IN_SET(cbe_enabled, me)); 208 CPUSET_ADD(cbe_enabled, me); 209 if (cbe_psm_timer_mode == TIMER_ONESHOT) 210 (*psm_timer_enable)(); 211 } 212 213 void 214 cbe_disable(void *arg) 215 { 216 processorid_t me = ((cpu_t *)arg)->cpu_id; 217 218 if (me == 0) { 219 /* 220 * If this is the boot CPU, we'll quietly refuse to disable 221 * our clock interrupt. 222 */ 223 return; 224 } 225 226 ASSERT(CPU_IN_SET(cbe_enabled, me)); 227 CPUSET_DEL(cbe_enabled, me); 228 if (cbe_psm_timer_mode == TIMER_ONESHOT) 229 (*psm_timer_disable)(); 230 } 231 232 /* 233 * Called only on CPU 0. This is done since TSCs can have deltas between 234 * different cpus see tsc_tick() 235 */ 236 void 237 cbe_hres_tick(void) 238 { 239 int s; 240 241 dtrace_hres_tick(); 242 243 /* 244 * Because hres_tick effectively locks hres_lock, we must be at the 245 * same PIL as that used for CLOCK_LOCK. 246 */ 247 s = splr(ipltospl(XC_HI_PIL)); 248 hres_tick(); 249 splx(s); 250 251 if ((cbe_ticks % hz) == 0) 252 (*hrtime_tick)(); 253 254 cbe_ticks++; 255 256 } 257 258 void 259 cbe_init(void) 260 { 261 cyc_backend_t cbe = { 262 cbe_configure, /* cyb_configure */ 263 NULL, /* cyb_unconfigure */ 264 cbe_enable, /* cyb_enable */ 265 cbe_disable, /* cyb_disable */ 266 cbe_reprogram, /* cyb_reprogram */ 267 cbe_softint, /* cyb_softint */ 268 cbe_set_level, /* cyb_set_level */ 269 cbe_restore_level, /* cyb_restore_level */ 270 cbe_xcall, /* cyb_xcall */ 271 NULL, /* cyb_suspend */ 272 NULL /* cyb_resume */ 273 }; 274 hrtime_t resolution; 275 cyc_handler_t hdlr; 276 cyc_time_t when; 277 278 cbe_vector = (*psm_get_clockirq)(CBE_HIGH_PIL); 279 280 CPUSET_ZERO(cbe_enabled); 281 282 resolution = (*clkinitf)(TIMER_ONESHOT, &cbe_psm_timer_mode); 283 284 mutex_enter(&cpu_lock); 285 cyclic_init(&cbe, resolution); 286 mutex_exit(&cpu_lock); 287 288 (void) add_avintr(NULL, CBE_HIGH_PIL, (avfunc)cbe_fire, 289 "cbe_fire_master", cbe_vector, 0, NULL, NULL, NULL); 290 291 if (psm_get_ipivect != NULL) { 292 (void) add_avintr(NULL, CBE_HIGH_PIL, (avfunc)cbe_fire, 293 "cbe_fire_slave", 294 (*psm_get_ipivect)(CBE_HIGH_PIL, PSM_INTR_IPI_HI), 295 0, NULL, NULL, NULL); 296 } 297 298 (void) add_avsoftintr((void *)&cbe_clock_hdl, CBE_LOCK_PIL, 299 (avfunc)cbe_softclock, "softclock", NULL, NULL); 300 301 (void) add_avsoftintr((void *)&cbe_low_hdl, CBE_LOW_PIL, 302 (avfunc)cbe_low_level, "low level", NULL, NULL); 303 304 mutex_enter(&cpu_lock); 305 306 hdlr.cyh_level = CY_HIGH_LEVEL; 307 hdlr.cyh_func = (cyc_func_t)cbe_hres_tick; 308 hdlr.cyh_arg = NULL; 309 310 when.cyt_when = 0; 311 when.cyt_interval = nsec_per_tick; 312 313 cbe_hres_cyclic = cyclic_add(&hdlr, &when); 314 315 /* bind to cpu 0, which is also the boot cpu */ 316 cyclic_bind(cbe_hres_cyclic, CPU, NULL); 317 318 if (psm_post_cyclic_setup != NULL) 319 (*psm_post_cyclic_setup)(NULL); 320 321 mutex_exit(&cpu_lock); 322 323 } 324