1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/clock.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/x_call.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/ivintr.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/cyclic.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/cyclic_impl.h> 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate uint32_t cbe_level14_inum; 45*7c478bd9Sstevel@tonic-gate cyclic_id_t cbe_hres_cyclic; 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate static hrtime_t cbe_hrtime_max; 48*7c478bd9Sstevel@tonic-gate static hrtime_t cbe_suspend_delta = 0; 49*7c478bd9Sstevel@tonic-gate static hrtime_t cbe_suspend_time = 0; 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate static uint64_t 52*7c478bd9Sstevel@tonic-gate hrtime2tick(hrtime_t ts) 53*7c478bd9Sstevel@tonic-gate { 54*7c478bd9Sstevel@tonic-gate hrtime_t q = ts / NANOSEC; 55*7c478bd9Sstevel@tonic-gate hrtime_t r = ts - (q * NANOSEC); 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate return (q * sys_tick_freq + ((r * sys_tick_freq) / NANOSEC)); 58*7c478bd9Sstevel@tonic-gate } 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate uint64_t 61*7c478bd9Sstevel@tonic-gate unscalehrtime(hrtime_t ts) 62*7c478bd9Sstevel@tonic-gate { 63*7c478bd9Sstevel@tonic-gate uint64_t unscale = 0; 64*7c478bd9Sstevel@tonic-gate hrtime_t rescale; 65*7c478bd9Sstevel@tonic-gate hrtime_t diff = ts; 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate while (diff > nsec_per_sys_tick) { 68*7c478bd9Sstevel@tonic-gate unscale += hrtime2tick(diff); 69*7c478bd9Sstevel@tonic-gate rescale = unscale; 70*7c478bd9Sstevel@tonic-gate scalehrtime(&rescale); 71*7c478bd9Sstevel@tonic-gate diff = ts - rescale; 72*7c478bd9Sstevel@tonic-gate } 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate return (unscale); 75*7c478bd9Sstevel@tonic-gate } 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate static int 78*7c478bd9Sstevel@tonic-gate cbe_level1() 79*7c478bd9Sstevel@tonic-gate { 80*7c478bd9Sstevel@tonic-gate cyclic_softint(CPU, CY_LOW_LEVEL); 81*7c478bd9Sstevel@tonic-gate return (1); 82*7c478bd9Sstevel@tonic-gate } 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate static int 85*7c478bd9Sstevel@tonic-gate cbe_level10() 86*7c478bd9Sstevel@tonic-gate { 87*7c478bd9Sstevel@tonic-gate cyclic_softint(CPU, CY_LOCK_LEVEL); 88*7c478bd9Sstevel@tonic-gate return (1); 89*7c478bd9Sstevel@tonic-gate } 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 92*7c478bd9Sstevel@tonic-gate static void 93*7c478bd9Sstevel@tonic-gate cbe_enable(cyb_arg_t arg) 94*7c478bd9Sstevel@tonic-gate { 95*7c478bd9Sstevel@tonic-gate int pstate_save = disable_vec_intr(); 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate intr_enqueue_req(PIL_14, cbe_level14_inum); 98*7c478bd9Sstevel@tonic-gate enable_vec_intr(pstate_save); 99*7c478bd9Sstevel@tonic-gate } 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 102*7c478bd9Sstevel@tonic-gate static void 103*7c478bd9Sstevel@tonic-gate cbe_disable(cyb_arg_t arg) 104*7c478bd9Sstevel@tonic-gate { 105*7c478bd9Sstevel@tonic-gate int pstate_save = disable_vec_intr(); 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate tickcmpr_disable(); 108*7c478bd9Sstevel@tonic-gate intr_dequeue_req(PIL_14, cbe_level14_inum); 109*7c478bd9Sstevel@tonic-gate enable_vec_intr(pstate_save); 110*7c478bd9Sstevel@tonic-gate } 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 113*7c478bd9Sstevel@tonic-gate static void 114*7c478bd9Sstevel@tonic-gate cbe_reprogram(cyb_arg_t arg, hrtime_t time) 115*7c478bd9Sstevel@tonic-gate { 116*7c478bd9Sstevel@tonic-gate if (time >= cbe_hrtime_max) 117*7c478bd9Sstevel@tonic-gate time = cbe_hrtime_max; 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate tickcmpr_set(unscalehrtime(time)); 120*7c478bd9Sstevel@tonic-gate } 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate static void 123*7c478bd9Sstevel@tonic-gate cbe_softint(cyb_arg_t arg, cyc_level_t level) 124*7c478bd9Sstevel@tonic-gate { 125*7c478bd9Sstevel@tonic-gate cbe_data_t *data = (cbe_data_t *)arg; 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate switch (level) { 128*7c478bd9Sstevel@tonic-gate case CY_LOW_LEVEL: 129*7c478bd9Sstevel@tonic-gate setsoftint(data->cbe_level1_inum); 130*7c478bd9Sstevel@tonic-gate break; 131*7c478bd9Sstevel@tonic-gate case CY_LOCK_LEVEL: 132*7c478bd9Sstevel@tonic-gate setsoftint(data->cbe_level10_inum); 133*7c478bd9Sstevel@tonic-gate break; 134*7c478bd9Sstevel@tonic-gate default: 135*7c478bd9Sstevel@tonic-gate panic("cbe_softint: unexpected soft level %d", level); 136*7c478bd9Sstevel@tonic-gate } 137*7c478bd9Sstevel@tonic-gate } 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 140*7c478bd9Sstevel@tonic-gate static cyc_cookie_t 141*7c478bd9Sstevel@tonic-gate cbe_set_level(cyb_arg_t arg, cyc_level_t level) 142*7c478bd9Sstevel@tonic-gate { 143*7c478bd9Sstevel@tonic-gate int ipl; 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate switch (level) { 146*7c478bd9Sstevel@tonic-gate case CY_LOW_LEVEL: 147*7c478bd9Sstevel@tonic-gate ipl = CBE_LOW_PIL; 148*7c478bd9Sstevel@tonic-gate break; 149*7c478bd9Sstevel@tonic-gate case CY_LOCK_LEVEL: 150*7c478bd9Sstevel@tonic-gate ipl = CBE_LOCK_PIL; 151*7c478bd9Sstevel@tonic-gate break; 152*7c478bd9Sstevel@tonic-gate case CY_HIGH_LEVEL: 153*7c478bd9Sstevel@tonic-gate ipl = CBE_HIGH_PIL; 154*7c478bd9Sstevel@tonic-gate break; 155*7c478bd9Sstevel@tonic-gate default: 156*7c478bd9Sstevel@tonic-gate panic("cbe_set_level: unexpected level %d", level); 157*7c478bd9Sstevel@tonic-gate } 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate return (splr(ipl)); 160*7c478bd9Sstevel@tonic-gate } 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 163*7c478bd9Sstevel@tonic-gate static void 164*7c478bd9Sstevel@tonic-gate cbe_restore_level(cyb_arg_t arg, cyc_cookie_t cookie) 165*7c478bd9Sstevel@tonic-gate { 166*7c478bd9Sstevel@tonic-gate splx(cookie); 167*7c478bd9Sstevel@tonic-gate } 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate static void 170*7c478bd9Sstevel@tonic-gate cbe_xcall_handler(uint64_t arg1, uint64_t arg2) 171*7c478bd9Sstevel@tonic-gate { 172*7c478bd9Sstevel@tonic-gate cyc_func_t func = (cyc_func_t)arg1; 173*7c478bd9Sstevel@tonic-gate void *arg = (void *)arg2; 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate (*func)(arg); 176*7c478bd9Sstevel@tonic-gate } 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 179*7c478bd9Sstevel@tonic-gate static void 180*7c478bd9Sstevel@tonic-gate cbe_xcall(cyb_arg_t arg, cpu_t *dest, cyc_func_t func, void *farg) 181*7c478bd9Sstevel@tonic-gate { 182*7c478bd9Sstevel@tonic-gate kpreempt_disable(); 183*7c478bd9Sstevel@tonic-gate xc_one(dest->cpu_id, cbe_xcall_handler, (uint64_t)func, (uint64_t)farg); 184*7c478bd9Sstevel@tonic-gate kpreempt_enable(); 185*7c478bd9Sstevel@tonic-gate } 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 188*7c478bd9Sstevel@tonic-gate static cyb_arg_t 189*7c478bd9Sstevel@tonic-gate cbe_configure(cpu_t *cpu) 190*7c478bd9Sstevel@tonic-gate { 191*7c478bd9Sstevel@tonic-gate cbe_data_t *new_data = kmem_alloc(sizeof (cbe_data_t), KM_SLEEP); 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate /* 194*7c478bd9Sstevel@tonic-gate * The setsoftint() code will refuse to post a soft interrupt if 195*7c478bd9Sstevel@tonic-gate * one is already pending for the specified inum. Given that we 196*7c478bd9Sstevel@tonic-gate * may have disjoint soft interrupts on different CPUs posted 197*7c478bd9Sstevel@tonic-gate * simultaneously, we allocate a new set of inums for each CPU. 198*7c478bd9Sstevel@tonic-gate */ 199*7c478bd9Sstevel@tonic-gate new_data->cbe_level10_inum = 200*7c478bd9Sstevel@tonic-gate add_softintr(PIL_10, (softintrfunc)cbe_level10, 0); 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate new_data->cbe_level1_inum = 203*7c478bd9Sstevel@tonic-gate add_softintr(PIL_1, (softintrfunc)cbe_level1, 0); 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate return (new_data); 206*7c478bd9Sstevel@tonic-gate } 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate static void 209*7c478bd9Sstevel@tonic-gate cbe_unconfigure(cyb_arg_t arg) 210*7c478bd9Sstevel@tonic-gate { 211*7c478bd9Sstevel@tonic-gate cbe_data_t *data = (cbe_data_t *)arg; 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate rem_softintr(data->cbe_level10_inum); 214*7c478bd9Sstevel@tonic-gate rem_softintr(data->cbe_level1_inum); 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate kmem_free(data, sizeof (cbe_data_t)); 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 220*7c478bd9Sstevel@tonic-gate static void 221*7c478bd9Sstevel@tonic-gate cbe_suspend(cyb_arg_t arg) 222*7c478bd9Sstevel@tonic-gate { 223*7c478bd9Sstevel@tonic-gate cbe_suspend_time = gethrtime_unscaled(); 224*7c478bd9Sstevel@tonic-gate cbe_suspend_delta = 0; 225*7c478bd9Sstevel@tonic-gate } 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 228*7c478bd9Sstevel@tonic-gate static void 229*7c478bd9Sstevel@tonic-gate cbe_resume(cyb_arg_t arg) 230*7c478bd9Sstevel@tonic-gate { 231*7c478bd9Sstevel@tonic-gate hrtime_t now; 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate /* 234*7c478bd9Sstevel@tonic-gate * If we're actually on a CPU which has apparently had %tick zeroed, 235*7c478bd9Sstevel@tonic-gate * we want to add cbe_suspend_delta to %tick. 236*7c478bd9Sstevel@tonic-gate */ 237*7c478bd9Sstevel@tonic-gate if ((now = gethrtime_unscaled()) < cbe_suspend_time) { 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate if (cbe_suspend_delta == 0) { 240*7c478bd9Sstevel@tonic-gate /* 241*7c478bd9Sstevel@tonic-gate * We're the first CPU to be resumed. We want %tick 242*7c478bd9Sstevel@tonic-gate * to be close to %tick when we suspended the system, 243*7c478bd9Sstevel@tonic-gate * so we'll figure out the delta which needs to be 244*7c478bd9Sstevel@tonic-gate * written to the register. All subsequent resumed 245*7c478bd9Sstevel@tonic-gate * CPUs will write the same delta. 246*7c478bd9Sstevel@tonic-gate */ 247*7c478bd9Sstevel@tonic-gate cbe_suspend_delta = cbe_suspend_time - now; 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate tick_write_delta(cbe_suspend_delta); 251*7c478bd9Sstevel@tonic-gate } 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate void 255*7c478bd9Sstevel@tonic-gate cbe_hres_tick(void) 256*7c478bd9Sstevel@tonic-gate { 257*7c478bd9Sstevel@tonic-gate dtrace_hres_tick(); 258*7c478bd9Sstevel@tonic-gate hres_tick(); 259*7c478bd9Sstevel@tonic-gate } 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate void 262*7c478bd9Sstevel@tonic-gate cbe_init(void) 263*7c478bd9Sstevel@tonic-gate { 264*7c478bd9Sstevel@tonic-gate cyc_handler_t hdlr; 265*7c478bd9Sstevel@tonic-gate cyc_time_t when; 266*7c478bd9Sstevel@tonic-gate hrtime_t resolution = NANOSEC / sys_tick_freq; 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate cyc_backend_t cbe = { 269*7c478bd9Sstevel@tonic-gate cbe_configure, /* cyb_configure */ 270*7c478bd9Sstevel@tonic-gate cbe_unconfigure, /* cyb_unconfigure */ 271*7c478bd9Sstevel@tonic-gate cbe_enable, /* cyb_enable */ 272*7c478bd9Sstevel@tonic-gate cbe_disable, /* cyb_disable */ 273*7c478bd9Sstevel@tonic-gate cbe_reprogram, /* cyb_reprogram */ 274*7c478bd9Sstevel@tonic-gate cbe_softint, /* cyb_softint */ 275*7c478bd9Sstevel@tonic-gate cbe_set_level, /* cyb_set_level */ 276*7c478bd9Sstevel@tonic-gate cbe_restore_level, /* cyb_restore_level */ 277*7c478bd9Sstevel@tonic-gate cbe_xcall, /* cyb_xcall */ 278*7c478bd9Sstevel@tonic-gate cbe_suspend, /* cyb_suspend */ 279*7c478bd9Sstevel@tonic-gate cbe_resume /* cyb_resume */ 280*7c478bd9Sstevel@tonic-gate }; 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate cbe_level14_inum = 283*7c478bd9Sstevel@tonic-gate add_softintr(CBE_HIGH_PIL, (softintrfunc)cbe_level14, 0); 284*7c478bd9Sstevel@tonic-gate cbe_hrtime_max = gethrtime_max(); 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate /* 287*7c478bd9Sstevel@tonic-gate * If sys_tick_freq > NANOSEC (i.e. we're on a CPU with a clock rate 288*7c478bd9Sstevel@tonic-gate * which exceeds 1 GHz), we'll specify the minimum resolution, 289*7c478bd9Sstevel@tonic-gate * 1 nanosecond. 290*7c478bd9Sstevel@tonic-gate */ 291*7c478bd9Sstevel@tonic-gate if (resolution == 0) 292*7c478bd9Sstevel@tonic-gate resolution = 1; 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 295*7c478bd9Sstevel@tonic-gate cyclic_init(&cbe, resolution); 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate /* 298*7c478bd9Sstevel@tonic-gate * Initialize hrtime_base and hres_last_tick to reasonable starting 299*7c478bd9Sstevel@tonic-gate * values. 300*7c478bd9Sstevel@tonic-gate */ 301*7c478bd9Sstevel@tonic-gate hrtime_base = gethrtime(); 302*7c478bd9Sstevel@tonic-gate hres_last_tick = gethrtime_unscaled(); 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate hdlr.cyh_level = CY_HIGH_LEVEL; 305*7c478bd9Sstevel@tonic-gate hdlr.cyh_func = (cyc_func_t)cbe_hres_tick; 306*7c478bd9Sstevel@tonic-gate hdlr.cyh_arg = NULL; 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate when.cyt_when = 0; 309*7c478bd9Sstevel@tonic-gate when.cyt_interval = nsec_per_tick; 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate cbe_hres_cyclic = cyclic_add(&hdlr, &when); 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate clkstart(); 316*7c478bd9Sstevel@tonic-gate } 317