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 52973Sgovinda * Common Development and Distribution License (the "License"). 62973Sgovinda * 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*10797SEric.Saxe@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <sys/param.h> 270Sstevel@tonic-gate #include <sys/time.h> 280Sstevel@tonic-gate #include <sys/systm.h> 290Sstevel@tonic-gate #include <sys/cmn_err.h> 300Sstevel@tonic-gate #include <sys/debug.h> 310Sstevel@tonic-gate #include <sys/clock.h> 320Sstevel@tonic-gate #include <sys/x_call.h> 330Sstevel@tonic-gate #include <sys/cpuvar.h> 340Sstevel@tonic-gate #include <sys/promif.h> 350Sstevel@tonic-gate #include <sys/kmem.h> 360Sstevel@tonic-gate #include <sys/machsystm.h> 370Sstevel@tonic-gate #include <sys/ivintr.h> 380Sstevel@tonic-gate #include <sys/cyclic.h> 390Sstevel@tonic-gate #include <sys/cyclic_impl.h> 400Sstevel@tonic-gate 412973Sgovinda uint64_t cbe_level14_inum; 420Sstevel@tonic-gate cyclic_id_t cbe_hres_cyclic; 430Sstevel@tonic-gate 440Sstevel@tonic-gate static hrtime_t cbe_hrtime_max; 450Sstevel@tonic-gate static hrtime_t cbe_suspend_delta = 0; 460Sstevel@tonic-gate static hrtime_t cbe_suspend_time = 0; 470Sstevel@tonic-gate 480Sstevel@tonic-gate static uint64_t 490Sstevel@tonic-gate hrtime2tick(hrtime_t ts) 500Sstevel@tonic-gate { 510Sstevel@tonic-gate hrtime_t q = ts / NANOSEC; 520Sstevel@tonic-gate hrtime_t r = ts - (q * NANOSEC); 530Sstevel@tonic-gate 540Sstevel@tonic-gate return (q * sys_tick_freq + ((r * sys_tick_freq) / NANOSEC)); 550Sstevel@tonic-gate } 560Sstevel@tonic-gate 57*10797SEric.Saxe@Sun.COM uint64_t 580Sstevel@tonic-gate unscalehrtime(hrtime_t ts) 590Sstevel@tonic-gate { 600Sstevel@tonic-gate uint64_t unscale = 0; 610Sstevel@tonic-gate hrtime_t rescale; 620Sstevel@tonic-gate hrtime_t diff = ts; 630Sstevel@tonic-gate 640Sstevel@tonic-gate while (diff > nsec_per_sys_tick) { 650Sstevel@tonic-gate unscale += hrtime2tick(diff); 660Sstevel@tonic-gate rescale = unscale; 670Sstevel@tonic-gate scalehrtime(&rescale); 680Sstevel@tonic-gate diff = ts - rescale; 690Sstevel@tonic-gate } 700Sstevel@tonic-gate 710Sstevel@tonic-gate return (unscale); 720Sstevel@tonic-gate } 730Sstevel@tonic-gate 740Sstevel@tonic-gate static int 750Sstevel@tonic-gate cbe_level1() 760Sstevel@tonic-gate { 770Sstevel@tonic-gate cyclic_softint(CPU, CY_LOW_LEVEL); 780Sstevel@tonic-gate return (1); 790Sstevel@tonic-gate } 800Sstevel@tonic-gate 810Sstevel@tonic-gate static int 820Sstevel@tonic-gate cbe_level10() 830Sstevel@tonic-gate { 840Sstevel@tonic-gate cyclic_softint(CPU, CY_LOCK_LEVEL); 850Sstevel@tonic-gate return (1); 860Sstevel@tonic-gate } 870Sstevel@tonic-gate 880Sstevel@tonic-gate /*ARGSUSED*/ 890Sstevel@tonic-gate static void 900Sstevel@tonic-gate cbe_enable(cyb_arg_t arg) 910Sstevel@tonic-gate { 920Sstevel@tonic-gate int pstate_save = disable_vec_intr(); 930Sstevel@tonic-gate 940Sstevel@tonic-gate intr_enqueue_req(PIL_14, cbe_level14_inum); 950Sstevel@tonic-gate enable_vec_intr(pstate_save); 960Sstevel@tonic-gate } 970Sstevel@tonic-gate 980Sstevel@tonic-gate /*ARGSUSED*/ 990Sstevel@tonic-gate static void 1000Sstevel@tonic-gate cbe_disable(cyb_arg_t arg) 1010Sstevel@tonic-gate { 1020Sstevel@tonic-gate int pstate_save = disable_vec_intr(); 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate tickcmpr_disable(); 1050Sstevel@tonic-gate intr_dequeue_req(PIL_14, cbe_level14_inum); 1060Sstevel@tonic-gate enable_vec_intr(pstate_save); 1070Sstevel@tonic-gate } 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate /*ARGSUSED*/ 1100Sstevel@tonic-gate static void 1110Sstevel@tonic-gate cbe_reprogram(cyb_arg_t arg, hrtime_t time) 1120Sstevel@tonic-gate { 1130Sstevel@tonic-gate if (time >= cbe_hrtime_max) 1140Sstevel@tonic-gate time = cbe_hrtime_max; 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate tickcmpr_set(unscalehrtime(time)); 1170Sstevel@tonic-gate } 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate static void 1200Sstevel@tonic-gate cbe_softint(cyb_arg_t arg, cyc_level_t level) 1210Sstevel@tonic-gate { 1220Sstevel@tonic-gate cbe_data_t *data = (cbe_data_t *)arg; 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate switch (level) { 1250Sstevel@tonic-gate case CY_LOW_LEVEL: 1260Sstevel@tonic-gate setsoftint(data->cbe_level1_inum); 1270Sstevel@tonic-gate break; 1280Sstevel@tonic-gate case CY_LOCK_LEVEL: 1290Sstevel@tonic-gate setsoftint(data->cbe_level10_inum); 1300Sstevel@tonic-gate break; 1310Sstevel@tonic-gate default: 1320Sstevel@tonic-gate panic("cbe_softint: unexpected soft level %d", level); 1330Sstevel@tonic-gate } 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate /*ARGSUSED*/ 1370Sstevel@tonic-gate static cyc_cookie_t 1380Sstevel@tonic-gate cbe_set_level(cyb_arg_t arg, cyc_level_t level) 1390Sstevel@tonic-gate { 1400Sstevel@tonic-gate int ipl; 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate switch (level) { 1430Sstevel@tonic-gate case CY_LOW_LEVEL: 1440Sstevel@tonic-gate ipl = CBE_LOW_PIL; 1450Sstevel@tonic-gate break; 1460Sstevel@tonic-gate case CY_LOCK_LEVEL: 1470Sstevel@tonic-gate ipl = CBE_LOCK_PIL; 1480Sstevel@tonic-gate break; 1490Sstevel@tonic-gate case CY_HIGH_LEVEL: 1500Sstevel@tonic-gate ipl = CBE_HIGH_PIL; 1510Sstevel@tonic-gate break; 1520Sstevel@tonic-gate default: 1530Sstevel@tonic-gate panic("cbe_set_level: unexpected level %d", level); 1540Sstevel@tonic-gate } 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate return (splr(ipl)); 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate /*ARGSUSED*/ 1600Sstevel@tonic-gate static void 1610Sstevel@tonic-gate cbe_restore_level(cyb_arg_t arg, cyc_cookie_t cookie) 1620Sstevel@tonic-gate { 1630Sstevel@tonic-gate splx(cookie); 1640Sstevel@tonic-gate } 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate static void 1670Sstevel@tonic-gate cbe_xcall_handler(uint64_t arg1, uint64_t arg2) 1680Sstevel@tonic-gate { 1690Sstevel@tonic-gate cyc_func_t func = (cyc_func_t)arg1; 1700Sstevel@tonic-gate void *arg = (void *)arg2; 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate (*func)(arg); 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate /*ARGSUSED*/ 1760Sstevel@tonic-gate static void 1770Sstevel@tonic-gate cbe_xcall(cyb_arg_t arg, cpu_t *dest, cyc_func_t func, void *farg) 1780Sstevel@tonic-gate { 1790Sstevel@tonic-gate kpreempt_disable(); 1800Sstevel@tonic-gate xc_one(dest->cpu_id, cbe_xcall_handler, (uint64_t)func, (uint64_t)farg); 1810Sstevel@tonic-gate kpreempt_enable(); 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate /*ARGSUSED*/ 1850Sstevel@tonic-gate static cyb_arg_t 1860Sstevel@tonic-gate cbe_configure(cpu_t *cpu) 1870Sstevel@tonic-gate { 1880Sstevel@tonic-gate cbe_data_t *new_data = kmem_alloc(sizeof (cbe_data_t), KM_SLEEP); 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate /* 1910Sstevel@tonic-gate * The setsoftint() code will refuse to post a soft interrupt if 1920Sstevel@tonic-gate * one is already pending for the specified inum. Given that we 1930Sstevel@tonic-gate * may have disjoint soft interrupts on different CPUs posted 1940Sstevel@tonic-gate * simultaneously, we allocate a new set of inums for each CPU. 1950Sstevel@tonic-gate */ 1962973Sgovinda new_data->cbe_level10_inum = add_softintr(PIL_10, 1972973Sgovinda (softintrfunc)cbe_level10, 0, SOFTINT_ST); 1980Sstevel@tonic-gate 1992973Sgovinda new_data->cbe_level1_inum = add_softintr(PIL_1, 2002973Sgovinda (softintrfunc)cbe_level1, 0, SOFTINT_ST); 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate return (new_data); 2030Sstevel@tonic-gate } 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate static void 2060Sstevel@tonic-gate cbe_unconfigure(cyb_arg_t arg) 2070Sstevel@tonic-gate { 2080Sstevel@tonic-gate cbe_data_t *data = (cbe_data_t *)arg; 2090Sstevel@tonic-gate 2102973Sgovinda (void) rem_softintr(data->cbe_level10_inum); 2112973Sgovinda (void) rem_softintr(data->cbe_level1_inum); 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate kmem_free(data, sizeof (cbe_data_t)); 2140Sstevel@tonic-gate } 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate /*ARGSUSED*/ 2170Sstevel@tonic-gate static void 2180Sstevel@tonic-gate cbe_suspend(cyb_arg_t arg) 2190Sstevel@tonic-gate { 2200Sstevel@tonic-gate cbe_suspend_time = gethrtime_unscaled(); 2210Sstevel@tonic-gate cbe_suspend_delta = 0; 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate /*ARGSUSED*/ 2250Sstevel@tonic-gate static void 2260Sstevel@tonic-gate cbe_resume(cyb_arg_t arg) 2270Sstevel@tonic-gate { 2280Sstevel@tonic-gate hrtime_t now; 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate /* 2310Sstevel@tonic-gate * If we're actually on a CPU which has apparently had %tick zeroed, 2320Sstevel@tonic-gate * we want to add cbe_suspend_delta to %tick. 2330Sstevel@tonic-gate */ 2340Sstevel@tonic-gate if ((now = gethrtime_unscaled()) < cbe_suspend_time) { 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate if (cbe_suspend_delta == 0) { 2370Sstevel@tonic-gate /* 2380Sstevel@tonic-gate * We're the first CPU to be resumed. We want %tick 2390Sstevel@tonic-gate * to be close to %tick when we suspended the system, 2400Sstevel@tonic-gate * so we'll figure out the delta which needs to be 2410Sstevel@tonic-gate * written to the register. All subsequent resumed 2420Sstevel@tonic-gate * CPUs will write the same delta. 2430Sstevel@tonic-gate */ 2440Sstevel@tonic-gate cbe_suspend_delta = cbe_suspend_time - now; 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate tick_write_delta(cbe_suspend_delta); 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate } 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate void 2520Sstevel@tonic-gate cbe_hres_tick(void) 2530Sstevel@tonic-gate { 2540Sstevel@tonic-gate dtrace_hres_tick(); 2550Sstevel@tonic-gate hres_tick(); 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate void 2597039Smrj cbe_init_pre(void) 2607039Smrj { 2617039Smrj /* Nothing to do on sparc */ 2627039Smrj } 2637039Smrj 2647039Smrj void 2650Sstevel@tonic-gate cbe_init(void) 2660Sstevel@tonic-gate { 2670Sstevel@tonic-gate cyc_handler_t hdlr; 2680Sstevel@tonic-gate cyc_time_t when; 2690Sstevel@tonic-gate hrtime_t resolution = NANOSEC / sys_tick_freq; 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate cyc_backend_t cbe = { 2720Sstevel@tonic-gate cbe_configure, /* cyb_configure */ 2730Sstevel@tonic-gate cbe_unconfigure, /* cyb_unconfigure */ 2740Sstevel@tonic-gate cbe_enable, /* cyb_enable */ 2750Sstevel@tonic-gate cbe_disable, /* cyb_disable */ 2760Sstevel@tonic-gate cbe_reprogram, /* cyb_reprogram */ 2770Sstevel@tonic-gate cbe_softint, /* cyb_softint */ 2780Sstevel@tonic-gate cbe_set_level, /* cyb_set_level */ 2790Sstevel@tonic-gate cbe_restore_level, /* cyb_restore_level */ 2800Sstevel@tonic-gate cbe_xcall, /* cyb_xcall */ 2810Sstevel@tonic-gate cbe_suspend, /* cyb_suspend */ 2820Sstevel@tonic-gate cbe_resume /* cyb_resume */ 2830Sstevel@tonic-gate }; 2840Sstevel@tonic-gate 2852973Sgovinda cbe_level14_inum = add_softintr(CBE_HIGH_PIL, 2862973Sgovinda (softintrfunc)cbe_level14, 0, SOFTINT_MT); 2870Sstevel@tonic-gate cbe_hrtime_max = gethrtime_max(); 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate /* 2900Sstevel@tonic-gate * If sys_tick_freq > NANOSEC (i.e. we're on a CPU with a clock rate 2910Sstevel@tonic-gate * which exceeds 1 GHz), we'll specify the minimum resolution, 2920Sstevel@tonic-gate * 1 nanosecond. 2930Sstevel@tonic-gate */ 2940Sstevel@tonic-gate if (resolution == 0) 2950Sstevel@tonic-gate resolution = 1; 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate mutex_enter(&cpu_lock); 2980Sstevel@tonic-gate cyclic_init(&cbe, resolution); 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate /* 3010Sstevel@tonic-gate * Initialize hrtime_base and hres_last_tick to reasonable starting 3020Sstevel@tonic-gate * values. 3030Sstevel@tonic-gate */ 3040Sstevel@tonic-gate hrtime_base = gethrtime(); 3050Sstevel@tonic-gate hres_last_tick = gethrtime_unscaled(); 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate hdlr.cyh_level = CY_HIGH_LEVEL; 3080Sstevel@tonic-gate hdlr.cyh_func = (cyc_func_t)cbe_hres_tick; 3090Sstevel@tonic-gate hdlr.cyh_arg = NULL; 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate when.cyt_when = 0; 3120Sstevel@tonic-gate when.cyt_interval = nsec_per_tick; 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate cbe_hres_cyclic = cyclic_add(&hdlr, &when); 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate mutex_exit(&cpu_lock); 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate clkstart(); 3190Sstevel@tonic-gate } 320