10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*2973Sgovinda * Common Development and Distribution License (the "License"). 6*2973Sgovinda * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*2973Sgovinda * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <sys/param.h> 290Sstevel@tonic-gate #include <sys/time.h> 300Sstevel@tonic-gate #include <sys/systm.h> 310Sstevel@tonic-gate #include <sys/cmn_err.h> 320Sstevel@tonic-gate #include <sys/debug.h> 330Sstevel@tonic-gate #include <sys/clock.h> 340Sstevel@tonic-gate #include <sys/x_call.h> 350Sstevel@tonic-gate #include <sys/cpuvar.h> 360Sstevel@tonic-gate #include <sys/promif.h> 370Sstevel@tonic-gate #include <sys/kmem.h> 380Sstevel@tonic-gate #include <sys/machsystm.h> 390Sstevel@tonic-gate #include <sys/ivintr.h> 400Sstevel@tonic-gate #include <sys/cyclic.h> 410Sstevel@tonic-gate #include <sys/cyclic_impl.h> 420Sstevel@tonic-gate 43*2973Sgovinda uint64_t cbe_level14_inum; 440Sstevel@tonic-gate cyclic_id_t cbe_hres_cyclic; 450Sstevel@tonic-gate 460Sstevel@tonic-gate static hrtime_t cbe_hrtime_max; 470Sstevel@tonic-gate static hrtime_t cbe_suspend_delta = 0; 480Sstevel@tonic-gate static hrtime_t cbe_suspend_time = 0; 490Sstevel@tonic-gate 500Sstevel@tonic-gate static uint64_t 510Sstevel@tonic-gate hrtime2tick(hrtime_t ts) 520Sstevel@tonic-gate { 530Sstevel@tonic-gate hrtime_t q = ts / NANOSEC; 540Sstevel@tonic-gate hrtime_t r = ts - (q * NANOSEC); 550Sstevel@tonic-gate 560Sstevel@tonic-gate return (q * sys_tick_freq + ((r * sys_tick_freq) / NANOSEC)); 570Sstevel@tonic-gate } 580Sstevel@tonic-gate 590Sstevel@tonic-gate uint64_t 600Sstevel@tonic-gate unscalehrtime(hrtime_t ts) 610Sstevel@tonic-gate { 620Sstevel@tonic-gate uint64_t unscale = 0; 630Sstevel@tonic-gate hrtime_t rescale; 640Sstevel@tonic-gate hrtime_t diff = ts; 650Sstevel@tonic-gate 660Sstevel@tonic-gate while (diff > nsec_per_sys_tick) { 670Sstevel@tonic-gate unscale += hrtime2tick(diff); 680Sstevel@tonic-gate rescale = unscale; 690Sstevel@tonic-gate scalehrtime(&rescale); 700Sstevel@tonic-gate diff = ts - rescale; 710Sstevel@tonic-gate } 720Sstevel@tonic-gate 730Sstevel@tonic-gate return (unscale); 740Sstevel@tonic-gate } 750Sstevel@tonic-gate 760Sstevel@tonic-gate static int 770Sstevel@tonic-gate cbe_level1() 780Sstevel@tonic-gate { 790Sstevel@tonic-gate cyclic_softint(CPU, CY_LOW_LEVEL); 800Sstevel@tonic-gate return (1); 810Sstevel@tonic-gate } 820Sstevel@tonic-gate 830Sstevel@tonic-gate static int 840Sstevel@tonic-gate cbe_level10() 850Sstevel@tonic-gate { 860Sstevel@tonic-gate cyclic_softint(CPU, CY_LOCK_LEVEL); 870Sstevel@tonic-gate return (1); 880Sstevel@tonic-gate } 890Sstevel@tonic-gate 900Sstevel@tonic-gate /*ARGSUSED*/ 910Sstevel@tonic-gate static void 920Sstevel@tonic-gate cbe_enable(cyb_arg_t arg) 930Sstevel@tonic-gate { 940Sstevel@tonic-gate int pstate_save = disable_vec_intr(); 950Sstevel@tonic-gate 960Sstevel@tonic-gate intr_enqueue_req(PIL_14, cbe_level14_inum); 970Sstevel@tonic-gate enable_vec_intr(pstate_save); 980Sstevel@tonic-gate } 990Sstevel@tonic-gate 1000Sstevel@tonic-gate /*ARGSUSED*/ 1010Sstevel@tonic-gate static void 1020Sstevel@tonic-gate cbe_disable(cyb_arg_t arg) 1030Sstevel@tonic-gate { 1040Sstevel@tonic-gate int pstate_save = disable_vec_intr(); 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate tickcmpr_disable(); 1070Sstevel@tonic-gate intr_dequeue_req(PIL_14, cbe_level14_inum); 1080Sstevel@tonic-gate enable_vec_intr(pstate_save); 1090Sstevel@tonic-gate } 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate /*ARGSUSED*/ 1120Sstevel@tonic-gate static void 1130Sstevel@tonic-gate cbe_reprogram(cyb_arg_t arg, hrtime_t time) 1140Sstevel@tonic-gate { 1150Sstevel@tonic-gate if (time >= cbe_hrtime_max) 1160Sstevel@tonic-gate time = cbe_hrtime_max; 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate tickcmpr_set(unscalehrtime(time)); 1190Sstevel@tonic-gate } 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate static void 1220Sstevel@tonic-gate cbe_softint(cyb_arg_t arg, cyc_level_t level) 1230Sstevel@tonic-gate { 1240Sstevel@tonic-gate cbe_data_t *data = (cbe_data_t *)arg; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate switch (level) { 1270Sstevel@tonic-gate case CY_LOW_LEVEL: 1280Sstevel@tonic-gate setsoftint(data->cbe_level1_inum); 1290Sstevel@tonic-gate break; 1300Sstevel@tonic-gate case CY_LOCK_LEVEL: 1310Sstevel@tonic-gate setsoftint(data->cbe_level10_inum); 1320Sstevel@tonic-gate break; 1330Sstevel@tonic-gate default: 1340Sstevel@tonic-gate panic("cbe_softint: unexpected soft level %d", level); 1350Sstevel@tonic-gate } 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate /*ARGSUSED*/ 1390Sstevel@tonic-gate static cyc_cookie_t 1400Sstevel@tonic-gate cbe_set_level(cyb_arg_t arg, cyc_level_t level) 1410Sstevel@tonic-gate { 1420Sstevel@tonic-gate int ipl; 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate switch (level) { 1450Sstevel@tonic-gate case CY_LOW_LEVEL: 1460Sstevel@tonic-gate ipl = CBE_LOW_PIL; 1470Sstevel@tonic-gate break; 1480Sstevel@tonic-gate case CY_LOCK_LEVEL: 1490Sstevel@tonic-gate ipl = CBE_LOCK_PIL; 1500Sstevel@tonic-gate break; 1510Sstevel@tonic-gate case CY_HIGH_LEVEL: 1520Sstevel@tonic-gate ipl = CBE_HIGH_PIL; 1530Sstevel@tonic-gate break; 1540Sstevel@tonic-gate default: 1550Sstevel@tonic-gate panic("cbe_set_level: unexpected level %d", level); 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate return (splr(ipl)); 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate /*ARGSUSED*/ 1620Sstevel@tonic-gate static void 1630Sstevel@tonic-gate cbe_restore_level(cyb_arg_t arg, cyc_cookie_t cookie) 1640Sstevel@tonic-gate { 1650Sstevel@tonic-gate splx(cookie); 1660Sstevel@tonic-gate } 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate static void 1690Sstevel@tonic-gate cbe_xcall_handler(uint64_t arg1, uint64_t arg2) 1700Sstevel@tonic-gate { 1710Sstevel@tonic-gate cyc_func_t func = (cyc_func_t)arg1; 1720Sstevel@tonic-gate void *arg = (void *)arg2; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate (*func)(arg); 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate /*ARGSUSED*/ 1780Sstevel@tonic-gate static void 1790Sstevel@tonic-gate cbe_xcall(cyb_arg_t arg, cpu_t *dest, cyc_func_t func, void *farg) 1800Sstevel@tonic-gate { 1810Sstevel@tonic-gate kpreempt_disable(); 1820Sstevel@tonic-gate xc_one(dest->cpu_id, cbe_xcall_handler, (uint64_t)func, (uint64_t)farg); 1830Sstevel@tonic-gate kpreempt_enable(); 1840Sstevel@tonic-gate } 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate /*ARGSUSED*/ 1870Sstevel@tonic-gate static cyb_arg_t 1880Sstevel@tonic-gate cbe_configure(cpu_t *cpu) 1890Sstevel@tonic-gate { 1900Sstevel@tonic-gate cbe_data_t *new_data = kmem_alloc(sizeof (cbe_data_t), KM_SLEEP); 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate /* 1930Sstevel@tonic-gate * The setsoftint() code will refuse to post a soft interrupt if 1940Sstevel@tonic-gate * one is already pending for the specified inum. Given that we 1950Sstevel@tonic-gate * may have disjoint soft interrupts on different CPUs posted 1960Sstevel@tonic-gate * simultaneously, we allocate a new set of inums for each CPU. 1970Sstevel@tonic-gate */ 198*2973Sgovinda new_data->cbe_level10_inum = add_softintr(PIL_10, 199*2973Sgovinda (softintrfunc)cbe_level10, 0, SOFTINT_ST); 2000Sstevel@tonic-gate 201*2973Sgovinda new_data->cbe_level1_inum = add_softintr(PIL_1, 202*2973Sgovinda (softintrfunc)cbe_level1, 0, SOFTINT_ST); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate return (new_data); 2050Sstevel@tonic-gate } 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate static void 2080Sstevel@tonic-gate cbe_unconfigure(cyb_arg_t arg) 2090Sstevel@tonic-gate { 2100Sstevel@tonic-gate cbe_data_t *data = (cbe_data_t *)arg; 2110Sstevel@tonic-gate 212*2973Sgovinda (void) rem_softintr(data->cbe_level10_inum); 213*2973Sgovinda (void) rem_softintr(data->cbe_level1_inum); 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate kmem_free(data, sizeof (cbe_data_t)); 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate /*ARGSUSED*/ 2190Sstevel@tonic-gate static void 2200Sstevel@tonic-gate cbe_suspend(cyb_arg_t arg) 2210Sstevel@tonic-gate { 2220Sstevel@tonic-gate cbe_suspend_time = gethrtime_unscaled(); 2230Sstevel@tonic-gate cbe_suspend_delta = 0; 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate /*ARGSUSED*/ 2270Sstevel@tonic-gate static void 2280Sstevel@tonic-gate cbe_resume(cyb_arg_t arg) 2290Sstevel@tonic-gate { 2300Sstevel@tonic-gate hrtime_t now; 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate /* 2330Sstevel@tonic-gate * If we're actually on a CPU which has apparently had %tick zeroed, 2340Sstevel@tonic-gate * we want to add cbe_suspend_delta to %tick. 2350Sstevel@tonic-gate */ 2360Sstevel@tonic-gate if ((now = gethrtime_unscaled()) < cbe_suspend_time) { 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate if (cbe_suspend_delta == 0) { 2390Sstevel@tonic-gate /* 2400Sstevel@tonic-gate * We're the first CPU to be resumed. We want %tick 2410Sstevel@tonic-gate * to be close to %tick when we suspended the system, 2420Sstevel@tonic-gate * so we'll figure out the delta which needs to be 2430Sstevel@tonic-gate * written to the register. All subsequent resumed 2440Sstevel@tonic-gate * CPUs will write the same delta. 2450Sstevel@tonic-gate */ 2460Sstevel@tonic-gate cbe_suspend_delta = cbe_suspend_time - now; 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate tick_write_delta(cbe_suspend_delta); 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate } 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate void 2540Sstevel@tonic-gate cbe_hres_tick(void) 2550Sstevel@tonic-gate { 2560Sstevel@tonic-gate dtrace_hres_tick(); 2570Sstevel@tonic-gate hres_tick(); 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate void 2610Sstevel@tonic-gate cbe_init(void) 2620Sstevel@tonic-gate { 2630Sstevel@tonic-gate cyc_handler_t hdlr; 2640Sstevel@tonic-gate cyc_time_t when; 2650Sstevel@tonic-gate hrtime_t resolution = NANOSEC / sys_tick_freq; 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate cyc_backend_t cbe = { 2680Sstevel@tonic-gate cbe_configure, /* cyb_configure */ 2690Sstevel@tonic-gate cbe_unconfigure, /* cyb_unconfigure */ 2700Sstevel@tonic-gate cbe_enable, /* cyb_enable */ 2710Sstevel@tonic-gate cbe_disable, /* cyb_disable */ 2720Sstevel@tonic-gate cbe_reprogram, /* cyb_reprogram */ 2730Sstevel@tonic-gate cbe_softint, /* cyb_softint */ 2740Sstevel@tonic-gate cbe_set_level, /* cyb_set_level */ 2750Sstevel@tonic-gate cbe_restore_level, /* cyb_restore_level */ 2760Sstevel@tonic-gate cbe_xcall, /* cyb_xcall */ 2770Sstevel@tonic-gate cbe_suspend, /* cyb_suspend */ 2780Sstevel@tonic-gate cbe_resume /* cyb_resume */ 2790Sstevel@tonic-gate }; 2800Sstevel@tonic-gate 281*2973Sgovinda cbe_level14_inum = add_softintr(CBE_HIGH_PIL, 282*2973Sgovinda (softintrfunc)cbe_level14, 0, SOFTINT_MT); 2830Sstevel@tonic-gate cbe_hrtime_max = gethrtime_max(); 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate /* 2860Sstevel@tonic-gate * If sys_tick_freq > NANOSEC (i.e. we're on a CPU with a clock rate 2870Sstevel@tonic-gate * which exceeds 1 GHz), we'll specify the minimum resolution, 2880Sstevel@tonic-gate * 1 nanosecond. 2890Sstevel@tonic-gate */ 2900Sstevel@tonic-gate if (resolution == 0) 2910Sstevel@tonic-gate resolution = 1; 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate mutex_enter(&cpu_lock); 2940Sstevel@tonic-gate cyclic_init(&cbe, resolution); 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate /* 2970Sstevel@tonic-gate * Initialize hrtime_base and hres_last_tick to reasonable starting 2980Sstevel@tonic-gate * values. 2990Sstevel@tonic-gate */ 3000Sstevel@tonic-gate hrtime_base = gethrtime(); 3010Sstevel@tonic-gate hres_last_tick = gethrtime_unscaled(); 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate hdlr.cyh_level = CY_HIGH_LEVEL; 3040Sstevel@tonic-gate hdlr.cyh_func = (cyc_func_t)cbe_hres_tick; 3050Sstevel@tonic-gate hdlr.cyh_arg = NULL; 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate when.cyt_when = 0; 3080Sstevel@tonic-gate when.cyt_interval = nsec_per_tick; 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate cbe_hres_cyclic = cyclic_add(&hdlr, &when); 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate mutex_exit(&cpu_lock); 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate clkstart(); 3150Sstevel@tonic-gate } 316