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 53446Smrj * Common Development and Distribution License (the "License"). 63446Smrj * 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 */ 213446Smrj 220Sstevel@tonic-gate /* 233446Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 263446Smrj 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <sys/systm.h> 300Sstevel@tonic-gate #include <sys/cyclic.h> 310Sstevel@tonic-gate #include <sys/cyclic_impl.h> 320Sstevel@tonic-gate #include <sys/spl.h> 330Sstevel@tonic-gate #include <sys/x_call.h> 340Sstevel@tonic-gate #include <sys/kmem.h> 350Sstevel@tonic-gate #include <sys/machsystm.h> 360Sstevel@tonic-gate #include <sys/smp_impldefs.h> 370Sstevel@tonic-gate #include <sys/psm_types.h> 383446Smrj #include <sys/psm.h> 390Sstevel@tonic-gate #include <sys/atomic.h> 400Sstevel@tonic-gate #include <sys/clock.h> 41*5295Srandyf #include <sys/x86_archext.h> 420Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 430Sstevel@tonic-gate #include <sys/ddi_intr.h> 44999Slq150181 #include <sys/avintr.h> 450Sstevel@tonic-gate 460Sstevel@tonic-gate static int cbe_vector; 470Sstevel@tonic-gate static int cbe_ticks = 0; 480Sstevel@tonic-gate 490Sstevel@tonic-gate static cyc_func_t volatile cbe_xcall_func; 500Sstevel@tonic-gate static cpu_t *volatile cbe_xcall_cpu; 510Sstevel@tonic-gate static void *cbe_xcall_farg; 520Sstevel@tonic-gate static cpuset_t cbe_enabled; 530Sstevel@tonic-gate 540Sstevel@tonic-gate static ddi_softint_hdl_impl_t cbe_low_hdl = 55999Slq150181 {0, NULL, NULL, NULL, 0, NULL, NULL, NULL}; 560Sstevel@tonic-gate static ddi_softint_hdl_impl_t cbe_clock_hdl = 57999Slq150181 {0, NULL, NULL, NULL, 0, NULL, NULL, NULL}; 580Sstevel@tonic-gate 590Sstevel@tonic-gate cyclic_id_t cbe_hres_cyclic; 600Sstevel@tonic-gate int cbe_psm_timer_mode = TIMER_ONESHOT; 610Sstevel@tonic-gate 62*5295Srandyf extern int tsc_gethrtime_enable; 63*5295Srandyf 640Sstevel@tonic-gate void cbe_hres_tick(void); 650Sstevel@tonic-gate 660Sstevel@tonic-gate int 670Sstevel@tonic-gate cbe_softclock(void) 680Sstevel@tonic-gate { 690Sstevel@tonic-gate cyclic_softint(CPU, CY_LOCK_LEVEL); 700Sstevel@tonic-gate return (1); 710Sstevel@tonic-gate } 720Sstevel@tonic-gate 730Sstevel@tonic-gate int 740Sstevel@tonic-gate cbe_low_level(void) 750Sstevel@tonic-gate { 760Sstevel@tonic-gate cpu_t *cpu = CPU; 770Sstevel@tonic-gate 780Sstevel@tonic-gate cyclic_softint(cpu, CY_LOW_LEVEL); 790Sstevel@tonic-gate return (1); 800Sstevel@tonic-gate } 810Sstevel@tonic-gate 820Sstevel@tonic-gate /* 830Sstevel@tonic-gate * We can be in cbe_fire() either due to a cyclic-induced cross call, or due 840Sstevel@tonic-gate * to the timer firing at level-14. Because cyclic_fire() can tolerate 850Sstevel@tonic-gate * spurious calls, it would not matter if we called cyclic_fire() in both 860Sstevel@tonic-gate * cases. 870Sstevel@tonic-gate */ 880Sstevel@tonic-gate int 890Sstevel@tonic-gate cbe_fire(void) 900Sstevel@tonic-gate { 910Sstevel@tonic-gate cpu_t *cpu = CPU; 920Sstevel@tonic-gate processorid_t me = cpu->cpu_id, i; 930Sstevel@tonic-gate int cross_call = (cbe_xcall_func != NULL && cbe_xcall_cpu == cpu); 940Sstevel@tonic-gate 950Sstevel@tonic-gate cyclic_fire(cpu); 960Sstevel@tonic-gate 970Sstevel@tonic-gate if (cbe_psm_timer_mode != TIMER_ONESHOT && me == 0 && !cross_call) { 980Sstevel@tonic-gate for (i = 1; i < NCPU; i++) { 993446Smrj if (CPU_IN_SET(cbe_enabled, i)) { 1003446Smrj XC_TRACE(TT_XC_CBE_FIRE, -1, i); 1010Sstevel@tonic-gate send_dirint(i, CBE_HIGH_PIL); 1023446Smrj } 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate } 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate if (cross_call) { 1070Sstevel@tonic-gate ASSERT(cbe_xcall_func != NULL && cbe_xcall_cpu == cpu); 1080Sstevel@tonic-gate (*cbe_xcall_func)(cbe_xcall_farg); 1090Sstevel@tonic-gate cbe_xcall_func = NULL; 1100Sstevel@tonic-gate cbe_xcall_cpu = NULL; 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate return (1); 1140Sstevel@tonic-gate } 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate /*ARGSUSED*/ 1170Sstevel@tonic-gate void 1180Sstevel@tonic-gate cbe_softint(void *arg, cyc_level_t level) 1190Sstevel@tonic-gate { 1200Sstevel@tonic-gate switch (level) { 1210Sstevel@tonic-gate case CY_LOW_LEVEL: 122999Slq150181 (*setsoftint)(CBE_LOW_PIL, cbe_low_hdl.ih_pending); 1230Sstevel@tonic-gate break; 1240Sstevel@tonic-gate case CY_LOCK_LEVEL: 125999Slq150181 (*setsoftint)(CBE_LOCK_PIL, cbe_clock_hdl.ih_pending); 1260Sstevel@tonic-gate break; 1270Sstevel@tonic-gate default: 1280Sstevel@tonic-gate panic("cbe_softint: unexpected soft level %d", level); 1290Sstevel@tonic-gate } 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate /*ARGSUSED*/ 1330Sstevel@tonic-gate void 1340Sstevel@tonic-gate cbe_reprogram(void *arg, hrtime_t time) 1350Sstevel@tonic-gate { 1360Sstevel@tonic-gate if (cbe_psm_timer_mode == TIMER_ONESHOT) 1370Sstevel@tonic-gate (*psm_timer_reprogram)(time); 1380Sstevel@tonic-gate } 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate /*ARGSUSED*/ 1410Sstevel@tonic-gate cyc_cookie_t 1420Sstevel@tonic-gate cbe_set_level(void *arg, cyc_level_t level) 1430Sstevel@tonic-gate { 1440Sstevel@tonic-gate int ipl; 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate switch (level) { 1470Sstevel@tonic-gate case CY_LOW_LEVEL: 1480Sstevel@tonic-gate ipl = CBE_LOW_PIL; 1490Sstevel@tonic-gate break; 1500Sstevel@tonic-gate case CY_LOCK_LEVEL: 1510Sstevel@tonic-gate ipl = CBE_LOCK_PIL; 1520Sstevel@tonic-gate break; 1530Sstevel@tonic-gate case CY_HIGH_LEVEL: 1540Sstevel@tonic-gate ipl = CBE_HIGH_PIL; 1550Sstevel@tonic-gate break; 1560Sstevel@tonic-gate default: 1570Sstevel@tonic-gate panic("cbe_set_level: unexpected level %d", level); 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate return (splr(ipltospl(ipl))); 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate /*ARGSUSED*/ 1640Sstevel@tonic-gate void 1650Sstevel@tonic-gate cbe_restore_level(void *arg, cyc_cookie_t cookie) 1660Sstevel@tonic-gate { 1670Sstevel@tonic-gate splx(cookie); 1680Sstevel@tonic-gate } 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate /*ARGSUSED*/ 1710Sstevel@tonic-gate void 1720Sstevel@tonic-gate cbe_xcall(void *arg, cpu_t *dest, cyc_func_t func, void *farg) 1730Sstevel@tonic-gate { 1740Sstevel@tonic-gate kpreempt_disable(); 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate if (dest == CPU) { 1770Sstevel@tonic-gate (*func)(farg); 1780Sstevel@tonic-gate kpreempt_enable(); 1790Sstevel@tonic-gate return; 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate ASSERT(cbe_xcall_func == NULL); 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate cbe_xcall_farg = farg; 1850Sstevel@tonic-gate membar_producer(); 1860Sstevel@tonic-gate cbe_xcall_cpu = dest; 1870Sstevel@tonic-gate cbe_xcall_func = func; 1880Sstevel@tonic-gate 1893446Smrj XC_TRACE(TT_XC_CBE_XCALL, -1, dest->cpu_id); 1900Sstevel@tonic-gate send_dirint(dest->cpu_id, CBE_HIGH_PIL); 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate while (cbe_xcall_func != NULL || cbe_xcall_cpu != NULL) 1930Sstevel@tonic-gate continue; 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate kpreempt_enable(); 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate ASSERT(cbe_xcall_func == NULL && cbe_xcall_cpu == NULL); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate void * 2010Sstevel@tonic-gate cbe_configure(cpu_t *cpu) 2020Sstevel@tonic-gate { 2030Sstevel@tonic-gate return (cpu); 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate 206*5295Srandyf #ifndef __xpv 207*5295Srandyf /* 208*5295Srandyf * declarations needed for time adjustment 209*5295Srandyf */ 210*5295Srandyf extern void tsc_suspend(void); 211*5295Srandyf extern void tsc_resume(void); 212*5295Srandyf /* 213*5295Srandyf * Call the resume function in the cyclic, instead of inline in the 214*5295Srandyf * resume path. 215*5295Srandyf */ 216*5295Srandyf extern int tsc_resume_in_cyclic; 217*5295Srandyf #endif 218*5295Srandyf 219*5295Srandyf /*ARGSUSED*/ 220*5295Srandyf static void 221*5295Srandyf cbe_suspend(cyb_arg_t arg) 222*5295Srandyf { 223*5295Srandyf #ifndef __xpv 224*5295Srandyf /* 225*5295Srandyf * This is an x86 backend, so let the tsc_suspend 226*5295Srandyf * that is specific to x86 platforms do the work. 227*5295Srandyf */ 228*5295Srandyf tsc_suspend(); 229*5295Srandyf #endif 230*5295Srandyf } 231*5295Srandyf 232*5295Srandyf /*ARGSUSED*/ 233*5295Srandyf static void 234*5295Srandyf cbe_resume(cyb_arg_t arg) 235*5295Srandyf { 236*5295Srandyf #ifndef __xpv 237*5295Srandyf if (tsc_resume_in_cyclic) { 238*5295Srandyf tsc_resume(); 239*5295Srandyf } 240*5295Srandyf #endif 241*5295Srandyf } 242*5295Srandyf 2430Sstevel@tonic-gate void 2440Sstevel@tonic-gate cbe_enable(void *arg) 2450Sstevel@tonic-gate { 2460Sstevel@tonic-gate processorid_t me = ((cpu_t *)arg)->cpu_id; 2470Sstevel@tonic-gate 2481389Sdmick /* neither enable nor disable cpu0 if TIMER_PERIODIC is set */ 2490Sstevel@tonic-gate if ((cbe_psm_timer_mode != TIMER_ONESHOT) && (me == 0)) 2500Sstevel@tonic-gate return; 2510Sstevel@tonic-gate 252*5295Srandyf /* 253*5295Srandyf * Added (me == 0) to the ASSERT because the timer isn't 254*5295Srandyf * disabled on CPU 0, and cbe_enable is called when we resume. 255*5295Srandyf */ 256*5295Srandyf ASSERT((me == 0) || !CPU_IN_SET(cbe_enabled, me)); 2570Sstevel@tonic-gate CPUSET_ADD(cbe_enabled, me); 2580Sstevel@tonic-gate if (cbe_psm_timer_mode == TIMER_ONESHOT) 2590Sstevel@tonic-gate (*psm_timer_enable)(); 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate void 2630Sstevel@tonic-gate cbe_disable(void *arg) 2640Sstevel@tonic-gate { 2650Sstevel@tonic-gate processorid_t me = ((cpu_t *)arg)->cpu_id; 2660Sstevel@tonic-gate 2671389Sdmick /* neither enable nor disable cpu0 if TIMER_PERIODIC is set */ 2681389Sdmick if ((cbe_psm_timer_mode != TIMER_ONESHOT) && (me == 0)) 2690Sstevel@tonic-gate return; 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate ASSERT(CPU_IN_SET(cbe_enabled, me)); 2720Sstevel@tonic-gate CPUSET_DEL(cbe_enabled, me); 2730Sstevel@tonic-gate if (cbe_psm_timer_mode == TIMER_ONESHOT) 2740Sstevel@tonic-gate (*psm_timer_disable)(); 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate /* 2781389Sdmick * Unbound cyclic, called once per tick (every nsec_per_tick ns). 2790Sstevel@tonic-gate */ 2800Sstevel@tonic-gate void 2810Sstevel@tonic-gate cbe_hres_tick(void) 2820Sstevel@tonic-gate { 2830Sstevel@tonic-gate int s; 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate dtrace_hres_tick(); 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate /* 2880Sstevel@tonic-gate * Because hres_tick effectively locks hres_lock, we must be at the 2890Sstevel@tonic-gate * same PIL as that used for CLOCK_LOCK. 2900Sstevel@tonic-gate */ 2910Sstevel@tonic-gate s = splr(ipltospl(XC_HI_PIL)); 2920Sstevel@tonic-gate hres_tick(); 2930Sstevel@tonic-gate splx(s); 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate if ((cbe_ticks % hz) == 0) 2960Sstevel@tonic-gate (*hrtime_tick)(); 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate cbe_ticks++; 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate } 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate void 3030Sstevel@tonic-gate cbe_init(void) 3040Sstevel@tonic-gate { 3050Sstevel@tonic-gate cyc_backend_t cbe = { 3060Sstevel@tonic-gate cbe_configure, /* cyb_configure */ 3070Sstevel@tonic-gate NULL, /* cyb_unconfigure */ 3080Sstevel@tonic-gate cbe_enable, /* cyb_enable */ 3090Sstevel@tonic-gate cbe_disable, /* cyb_disable */ 3100Sstevel@tonic-gate cbe_reprogram, /* cyb_reprogram */ 3110Sstevel@tonic-gate cbe_softint, /* cyb_softint */ 3120Sstevel@tonic-gate cbe_set_level, /* cyb_set_level */ 3130Sstevel@tonic-gate cbe_restore_level, /* cyb_restore_level */ 3140Sstevel@tonic-gate cbe_xcall, /* cyb_xcall */ 315*5295Srandyf cbe_suspend, /* cyb_suspend */ 316*5295Srandyf cbe_resume /* cyb_resume */ 3170Sstevel@tonic-gate }; 3180Sstevel@tonic-gate hrtime_t resolution; 3190Sstevel@tonic-gate cyc_handler_t hdlr; 3200Sstevel@tonic-gate cyc_time_t when; 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate cbe_vector = (*psm_get_clockirq)(CBE_HIGH_PIL); 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate CPUSET_ZERO(cbe_enabled); 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate resolution = (*clkinitf)(TIMER_ONESHOT, &cbe_psm_timer_mode); 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate mutex_enter(&cpu_lock); 3290Sstevel@tonic-gate cyclic_init(&cbe, resolution); 3300Sstevel@tonic-gate mutex_exit(&cpu_lock); 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate (void) add_avintr(NULL, CBE_HIGH_PIL, (avfunc)cbe_fire, 333916Sschwartz "cbe_fire_master", cbe_vector, 0, NULL, NULL, NULL); 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate if (psm_get_ipivect != NULL) { 3360Sstevel@tonic-gate (void) add_avintr(NULL, CBE_HIGH_PIL, (avfunc)cbe_fire, 3370Sstevel@tonic-gate "cbe_fire_slave", 3380Sstevel@tonic-gate (*psm_get_ipivect)(CBE_HIGH_PIL, PSM_INTR_IPI_HI), 339916Sschwartz 0, NULL, NULL, NULL); 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate (void) add_avsoftintr((void *)&cbe_clock_hdl, CBE_LOCK_PIL, 3430Sstevel@tonic-gate (avfunc)cbe_softclock, "softclock", NULL, NULL); 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate (void) add_avsoftintr((void *)&cbe_low_hdl, CBE_LOW_PIL, 3460Sstevel@tonic-gate (avfunc)cbe_low_level, "low level", NULL, NULL); 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate mutex_enter(&cpu_lock); 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate hdlr.cyh_level = CY_HIGH_LEVEL; 3510Sstevel@tonic-gate hdlr.cyh_func = (cyc_func_t)cbe_hres_tick; 3520Sstevel@tonic-gate hdlr.cyh_arg = NULL; 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate when.cyt_when = 0; 3550Sstevel@tonic-gate when.cyt_interval = nsec_per_tick; 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate cbe_hres_cyclic = cyclic_add(&hdlr, &when); 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate if (psm_post_cyclic_setup != NULL) 3600Sstevel@tonic-gate (*psm_post_cyclic_setup)(NULL); 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate mutex_exit(&cpu_lock); 3630Sstevel@tonic-gate } 364