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 #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 /* neither enable nor disable cpu0 if TIMER_PERIODIC is set */ 205 if ((cbe_psm_timer_mode != TIMER_ONESHOT) && (me == 0)) 206 return; 207 208 ASSERT(!CPU_IN_SET(cbe_enabled, me)); 209 CPUSET_ADD(cbe_enabled, me); 210 if (cbe_psm_timer_mode == TIMER_ONESHOT) 211 (*psm_timer_enable)(); 212 } 213 214 void 215 cbe_disable(void *arg) 216 { 217 processorid_t me = ((cpu_t *)arg)->cpu_id; 218 219 /* neither enable nor disable cpu0 if TIMER_PERIODIC is set */ 220 if ((cbe_psm_timer_mode != TIMER_ONESHOT) && (me == 0)) 221 return; 222 223 ASSERT(CPU_IN_SET(cbe_enabled, me)); 224 CPUSET_DEL(cbe_enabled, me); 225 if (cbe_psm_timer_mode == TIMER_ONESHOT) 226 (*psm_timer_disable)(); 227 } 228 229 /* 230 * Unbound cyclic, called once per tick (every nsec_per_tick ns). 231 */ 232 void 233 cbe_hres_tick(void) 234 { 235 int s; 236 237 dtrace_hres_tick(); 238 239 /* 240 * Because hres_tick effectively locks hres_lock, we must be at the 241 * same PIL as that used for CLOCK_LOCK. 242 */ 243 s = splr(ipltospl(XC_HI_PIL)); 244 hres_tick(); 245 splx(s); 246 247 if ((cbe_ticks % hz) == 0) 248 (*hrtime_tick)(); 249 250 cbe_ticks++; 251 252 } 253 254 void 255 cbe_init(void) 256 { 257 cyc_backend_t cbe = { 258 cbe_configure, /* cyb_configure */ 259 NULL, /* cyb_unconfigure */ 260 cbe_enable, /* cyb_enable */ 261 cbe_disable, /* cyb_disable */ 262 cbe_reprogram, /* cyb_reprogram */ 263 cbe_softint, /* cyb_softint */ 264 cbe_set_level, /* cyb_set_level */ 265 cbe_restore_level, /* cyb_restore_level */ 266 cbe_xcall, /* cyb_xcall */ 267 NULL, /* cyb_suspend */ 268 NULL /* cyb_resume */ 269 }; 270 hrtime_t resolution; 271 cyc_handler_t hdlr; 272 cyc_time_t when; 273 274 cbe_vector = (*psm_get_clockirq)(CBE_HIGH_PIL); 275 276 CPUSET_ZERO(cbe_enabled); 277 278 resolution = (*clkinitf)(TIMER_ONESHOT, &cbe_psm_timer_mode); 279 280 mutex_enter(&cpu_lock); 281 cyclic_init(&cbe, resolution); 282 mutex_exit(&cpu_lock); 283 284 (void) add_avintr(NULL, CBE_HIGH_PIL, (avfunc)cbe_fire, 285 "cbe_fire_master", cbe_vector, 0, NULL, NULL, NULL); 286 287 if (psm_get_ipivect != NULL) { 288 (void) add_avintr(NULL, CBE_HIGH_PIL, (avfunc)cbe_fire, 289 "cbe_fire_slave", 290 (*psm_get_ipivect)(CBE_HIGH_PIL, PSM_INTR_IPI_HI), 291 0, NULL, NULL, NULL); 292 } 293 294 (void) add_avsoftintr((void *)&cbe_clock_hdl, CBE_LOCK_PIL, 295 (avfunc)cbe_softclock, "softclock", NULL, NULL); 296 297 (void) add_avsoftintr((void *)&cbe_low_hdl, CBE_LOW_PIL, 298 (avfunc)cbe_low_level, "low level", NULL, NULL); 299 300 mutex_enter(&cpu_lock); 301 302 hdlr.cyh_level = CY_HIGH_LEVEL; 303 hdlr.cyh_func = (cyc_func_t)cbe_hres_tick; 304 hdlr.cyh_arg = NULL; 305 306 when.cyt_when = 0; 307 when.cyt_interval = nsec_per_tick; 308 309 cbe_hres_cyclic = cyclic_add(&hdlr, &when); 310 311 if (psm_post_cyclic_setup != NULL) 312 (*psm_post_cyclic_setup)(NULL); 313 314 mutex_exit(&cpu_lock); 315 316 } 317