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 /*
238566SMadhavan.Venkataraman@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
263446Smrj
270Sstevel@tonic-gate #include <sys/systm.h>
280Sstevel@tonic-gate #include <sys/cyclic.h>
290Sstevel@tonic-gate #include <sys/cyclic_impl.h>
300Sstevel@tonic-gate #include <sys/spl.h>
310Sstevel@tonic-gate #include <sys/x_call.h>
320Sstevel@tonic-gate #include <sys/kmem.h>
330Sstevel@tonic-gate #include <sys/machsystm.h>
340Sstevel@tonic-gate #include <sys/smp_impldefs.h>
350Sstevel@tonic-gate #include <sys/psm_types.h>
363446Smrj #include <sys/psm.h>
370Sstevel@tonic-gate #include <sys/atomic.h>
380Sstevel@tonic-gate #include <sys/clock.h>
395295Srandyf #include <sys/x86_archext.h>
400Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
410Sstevel@tonic-gate #include <sys/ddi_intr.h>
42999Slq150181 #include <sys/avintr.h>
43*12004Sjiang.liu@intel.com #include <sys/note.h>
440Sstevel@tonic-gate
450Sstevel@tonic-gate static int cbe_vector;
460Sstevel@tonic-gate static int cbe_ticks = 0;
470Sstevel@tonic-gate
488048SMadhavan.Venkataraman@Sun.COM /*
498048SMadhavan.Venkataraman@Sun.COM * cbe_xcall_lock is used to protect the xcall globals since the cyclic
508048SMadhavan.Venkataraman@Sun.COM * reprogramming API does not use cpu_lock.
518048SMadhavan.Venkataraman@Sun.COM */
528048SMadhavan.Venkataraman@Sun.COM static kmutex_t cbe_xcall_lock;
530Sstevel@tonic-gate static cyc_func_t volatile cbe_xcall_func;
540Sstevel@tonic-gate static cpu_t *volatile cbe_xcall_cpu;
550Sstevel@tonic-gate static void *cbe_xcall_farg;
560Sstevel@tonic-gate static cpuset_t cbe_enabled;
570Sstevel@tonic-gate
580Sstevel@tonic-gate static ddi_softint_hdl_impl_t cbe_low_hdl =
59999Slq150181 {0, NULL, NULL, NULL, 0, NULL, NULL, NULL};
600Sstevel@tonic-gate static ddi_softint_hdl_impl_t cbe_clock_hdl =
61999Slq150181 {0, NULL, NULL, NULL, 0, NULL, NULL, NULL};
620Sstevel@tonic-gate
630Sstevel@tonic-gate cyclic_id_t cbe_hres_cyclic;
640Sstevel@tonic-gate int cbe_psm_timer_mode = TIMER_ONESHOT;
657039Smrj static hrtime_t cbe_timer_resolution;
660Sstevel@tonic-gate
675295Srandyf extern int tsc_gethrtime_enable;
685295Srandyf
690Sstevel@tonic-gate void cbe_hres_tick(void);
700Sstevel@tonic-gate
710Sstevel@tonic-gate int
cbe_softclock(void)720Sstevel@tonic-gate cbe_softclock(void)
730Sstevel@tonic-gate {
740Sstevel@tonic-gate cyclic_softint(CPU, CY_LOCK_LEVEL);
750Sstevel@tonic-gate return (1);
760Sstevel@tonic-gate }
770Sstevel@tonic-gate
780Sstevel@tonic-gate int
cbe_low_level(void)790Sstevel@tonic-gate cbe_low_level(void)
800Sstevel@tonic-gate {
810Sstevel@tonic-gate cpu_t *cpu = CPU;
820Sstevel@tonic-gate
830Sstevel@tonic-gate cyclic_softint(cpu, CY_LOW_LEVEL);
840Sstevel@tonic-gate return (1);
850Sstevel@tonic-gate }
860Sstevel@tonic-gate
870Sstevel@tonic-gate /*
880Sstevel@tonic-gate * We can be in cbe_fire() either due to a cyclic-induced cross call, or due
890Sstevel@tonic-gate * to the timer firing at level-14. Because cyclic_fire() can tolerate
900Sstevel@tonic-gate * spurious calls, it would not matter if we called cyclic_fire() in both
910Sstevel@tonic-gate * cases.
920Sstevel@tonic-gate */
930Sstevel@tonic-gate int
cbe_fire(void)940Sstevel@tonic-gate cbe_fire(void)
950Sstevel@tonic-gate {
960Sstevel@tonic-gate cpu_t *cpu = CPU;
970Sstevel@tonic-gate processorid_t me = cpu->cpu_id, i;
980Sstevel@tonic-gate int cross_call = (cbe_xcall_func != NULL && cbe_xcall_cpu == cpu);
990Sstevel@tonic-gate
1000Sstevel@tonic-gate cyclic_fire(cpu);
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate if (cbe_psm_timer_mode != TIMER_ONESHOT && me == 0 && !cross_call) {
1030Sstevel@tonic-gate for (i = 1; i < NCPU; i++) {
1043446Smrj if (CPU_IN_SET(cbe_enabled, i)) {
1050Sstevel@tonic-gate send_dirint(i, CBE_HIGH_PIL);
1063446Smrj }
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate if (cross_call) {
1110Sstevel@tonic-gate ASSERT(cbe_xcall_func != NULL && cbe_xcall_cpu == cpu);
1120Sstevel@tonic-gate (*cbe_xcall_func)(cbe_xcall_farg);
1130Sstevel@tonic-gate cbe_xcall_func = NULL;
1140Sstevel@tonic-gate cbe_xcall_cpu = NULL;
1150Sstevel@tonic-gate }
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate return (1);
1180Sstevel@tonic-gate }
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate /*ARGSUSED*/
1210Sstevel@tonic-gate void
cbe_softint(void * arg,cyc_level_t level)1220Sstevel@tonic-gate cbe_softint(void *arg, cyc_level_t level)
1230Sstevel@tonic-gate {
1240Sstevel@tonic-gate switch (level) {
1250Sstevel@tonic-gate case CY_LOW_LEVEL:
126999Slq150181 (*setsoftint)(CBE_LOW_PIL, cbe_low_hdl.ih_pending);
1270Sstevel@tonic-gate break;
1280Sstevel@tonic-gate case CY_LOCK_LEVEL:
129999Slq150181 (*setsoftint)(CBE_LOCK_PIL, cbe_clock_hdl.ih_pending);
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 void
cbe_reprogram(void * arg,hrtime_t time)1380Sstevel@tonic-gate cbe_reprogram(void *arg, hrtime_t time)
1390Sstevel@tonic-gate {
1400Sstevel@tonic-gate if (cbe_psm_timer_mode == TIMER_ONESHOT)
1410Sstevel@tonic-gate (*psm_timer_reprogram)(time);
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate /*ARGSUSED*/
1450Sstevel@tonic-gate cyc_cookie_t
cbe_set_level(void * arg,cyc_level_t level)1460Sstevel@tonic-gate cbe_set_level(void *arg, cyc_level_t level)
1470Sstevel@tonic-gate {
1480Sstevel@tonic-gate int ipl;
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate switch (level) {
1510Sstevel@tonic-gate case CY_LOW_LEVEL:
1520Sstevel@tonic-gate ipl = CBE_LOW_PIL;
1530Sstevel@tonic-gate break;
1540Sstevel@tonic-gate case CY_LOCK_LEVEL:
1550Sstevel@tonic-gate ipl = CBE_LOCK_PIL;
1560Sstevel@tonic-gate break;
1570Sstevel@tonic-gate case CY_HIGH_LEVEL:
1580Sstevel@tonic-gate ipl = CBE_HIGH_PIL;
1590Sstevel@tonic-gate break;
1600Sstevel@tonic-gate default:
1610Sstevel@tonic-gate panic("cbe_set_level: unexpected level %d", level);
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate return (splr(ipltospl(ipl)));
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate /*ARGSUSED*/
1680Sstevel@tonic-gate void
cbe_restore_level(void * arg,cyc_cookie_t cookie)1690Sstevel@tonic-gate cbe_restore_level(void *arg, cyc_cookie_t cookie)
1700Sstevel@tonic-gate {
1710Sstevel@tonic-gate splx(cookie);
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate /*ARGSUSED*/
1750Sstevel@tonic-gate void
cbe_xcall(void * arg,cpu_t * dest,cyc_func_t func,void * farg)1760Sstevel@tonic-gate cbe_xcall(void *arg, cpu_t *dest, cyc_func_t func, void *farg)
1770Sstevel@tonic-gate {
1780Sstevel@tonic-gate kpreempt_disable();
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate if (dest == CPU) {
1810Sstevel@tonic-gate (*func)(farg);
1820Sstevel@tonic-gate kpreempt_enable();
1830Sstevel@tonic-gate return;
1840Sstevel@tonic-gate }
1850Sstevel@tonic-gate
1868048SMadhavan.Venkataraman@Sun.COM mutex_enter(&cbe_xcall_lock);
1878048SMadhavan.Venkataraman@Sun.COM
1880Sstevel@tonic-gate ASSERT(cbe_xcall_func == NULL);
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate cbe_xcall_farg = farg;
1910Sstevel@tonic-gate membar_producer();
1920Sstevel@tonic-gate cbe_xcall_cpu = dest;
1930Sstevel@tonic-gate cbe_xcall_func = func;
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate send_dirint(dest->cpu_id, CBE_HIGH_PIL);
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate while (cbe_xcall_func != NULL || cbe_xcall_cpu != NULL)
1980Sstevel@tonic-gate continue;
1990Sstevel@tonic-gate
2008048SMadhavan.Venkataraman@Sun.COM mutex_exit(&cbe_xcall_lock);
2018048SMadhavan.Venkataraman@Sun.COM
2020Sstevel@tonic-gate kpreempt_enable();
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate void *
cbe_configure(cpu_t * cpu)2060Sstevel@tonic-gate cbe_configure(cpu_t *cpu)
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate return (cpu);
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate
211*12004Sjiang.liu@intel.com void
cbe_unconfigure(void * arg)212*12004Sjiang.liu@intel.com cbe_unconfigure(void *arg)
213*12004Sjiang.liu@intel.com {
214*12004Sjiang.liu@intel.com _NOTE(ARGUNUSED(arg));
215*12004Sjiang.liu@intel.com ASSERT(!CPU_IN_SET(cbe_enabled, ((cpu_t *)arg)->cpu_id));
216*12004Sjiang.liu@intel.com }
217*12004Sjiang.liu@intel.com
2185295Srandyf #ifndef __xpv
2195295Srandyf /*
2205295Srandyf * declarations needed for time adjustment
2215295Srandyf */
2225295Srandyf extern void tsc_suspend(void);
2235295Srandyf extern void tsc_resume(void);
2245295Srandyf /*
2255295Srandyf * Call the resume function in the cyclic, instead of inline in the
2265295Srandyf * resume path.
2275295Srandyf */
2285295Srandyf extern int tsc_resume_in_cyclic;
2295295Srandyf #endif
2305295Srandyf
2315295Srandyf /*ARGSUSED*/
2325295Srandyf static void
cbe_suspend(cyb_arg_t arg)2335295Srandyf cbe_suspend(cyb_arg_t arg)
2345295Srandyf {
2355295Srandyf #ifndef __xpv
2365295Srandyf /*
2375295Srandyf * This is an x86 backend, so let the tsc_suspend
2385295Srandyf * that is specific to x86 platforms do the work.
2395295Srandyf */
2405295Srandyf tsc_suspend();
2415295Srandyf #endif
2425295Srandyf }
2435295Srandyf
2445295Srandyf /*ARGSUSED*/
2455295Srandyf static void
cbe_resume(cyb_arg_t arg)2465295Srandyf cbe_resume(cyb_arg_t arg)
2475295Srandyf {
2485295Srandyf #ifndef __xpv
2495295Srandyf if (tsc_resume_in_cyclic) {
2505295Srandyf tsc_resume();
2515295Srandyf }
2525295Srandyf #endif
2535295Srandyf }
2545295Srandyf
2550Sstevel@tonic-gate void
cbe_enable(void * arg)2560Sstevel@tonic-gate cbe_enable(void *arg)
2570Sstevel@tonic-gate {
2580Sstevel@tonic-gate processorid_t me = ((cpu_t *)arg)->cpu_id;
2590Sstevel@tonic-gate
2601389Sdmick /* neither enable nor disable cpu0 if TIMER_PERIODIC is set */
2610Sstevel@tonic-gate if ((cbe_psm_timer_mode != TIMER_ONESHOT) && (me == 0))
2620Sstevel@tonic-gate return;
2630Sstevel@tonic-gate
2645295Srandyf /*
2655295Srandyf * Added (me == 0) to the ASSERT because the timer isn't
2665295Srandyf * disabled on CPU 0, and cbe_enable is called when we resume.
2675295Srandyf */
2685295Srandyf ASSERT((me == 0) || !CPU_IN_SET(cbe_enabled, me));
2690Sstevel@tonic-gate CPUSET_ADD(cbe_enabled, me);
2700Sstevel@tonic-gate if (cbe_psm_timer_mode == TIMER_ONESHOT)
2710Sstevel@tonic-gate (*psm_timer_enable)();
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate void
cbe_disable(void * arg)2750Sstevel@tonic-gate cbe_disable(void *arg)
2760Sstevel@tonic-gate {
2770Sstevel@tonic-gate processorid_t me = ((cpu_t *)arg)->cpu_id;
2780Sstevel@tonic-gate
2791389Sdmick /* neither enable nor disable cpu0 if TIMER_PERIODIC is set */
2801389Sdmick if ((cbe_psm_timer_mode != TIMER_ONESHOT) && (me == 0))
2810Sstevel@tonic-gate return;
2820Sstevel@tonic-gate
2830Sstevel@tonic-gate ASSERT(CPU_IN_SET(cbe_enabled, me));
2840Sstevel@tonic-gate CPUSET_DEL(cbe_enabled, me);
2850Sstevel@tonic-gate if (cbe_psm_timer_mode == TIMER_ONESHOT)
2860Sstevel@tonic-gate (*psm_timer_disable)();
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate /*
2901389Sdmick * Unbound cyclic, called once per tick (every nsec_per_tick ns).
2910Sstevel@tonic-gate */
2920Sstevel@tonic-gate void
cbe_hres_tick(void)2930Sstevel@tonic-gate cbe_hres_tick(void)
2940Sstevel@tonic-gate {
2950Sstevel@tonic-gate int s;
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate dtrace_hres_tick();
2980Sstevel@tonic-gate
2990Sstevel@tonic-gate /*
3000Sstevel@tonic-gate * Because hres_tick effectively locks hres_lock, we must be at the
3010Sstevel@tonic-gate * same PIL as that used for CLOCK_LOCK.
3020Sstevel@tonic-gate */
3030Sstevel@tonic-gate s = splr(ipltospl(XC_HI_PIL));
3040Sstevel@tonic-gate hres_tick();
3050Sstevel@tonic-gate splx(s);
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate if ((cbe_ticks % hz) == 0)
3080Sstevel@tonic-gate (*hrtime_tick)();
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate cbe_ticks++;
3110Sstevel@tonic-gate
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate void
cbe_init_pre(void)3157039Smrj cbe_init_pre(void)
3167039Smrj {
3177039Smrj cbe_vector = (*psm_get_clockirq)(CBE_HIGH_PIL);
3187039Smrj
3197039Smrj CPUSET_ZERO(cbe_enabled);
3207039Smrj
3217039Smrj cbe_timer_resolution = (*clkinitf)(TIMER_ONESHOT, &cbe_psm_timer_mode);
3227039Smrj }
3237039Smrj
3247039Smrj void
cbe_init(void)3250Sstevel@tonic-gate cbe_init(void)
3260Sstevel@tonic-gate {
3270Sstevel@tonic-gate cyc_backend_t cbe = {
3280Sstevel@tonic-gate cbe_configure, /* cyb_configure */
329*12004Sjiang.liu@intel.com cbe_unconfigure, /* cyb_unconfigure */
3300Sstevel@tonic-gate cbe_enable, /* cyb_enable */
3310Sstevel@tonic-gate cbe_disable, /* cyb_disable */
3320Sstevel@tonic-gate cbe_reprogram, /* cyb_reprogram */
3330Sstevel@tonic-gate cbe_softint, /* cyb_softint */
3340Sstevel@tonic-gate cbe_set_level, /* cyb_set_level */
3350Sstevel@tonic-gate cbe_restore_level, /* cyb_restore_level */
3360Sstevel@tonic-gate cbe_xcall, /* cyb_xcall */
3375295Srandyf cbe_suspend, /* cyb_suspend */
3385295Srandyf cbe_resume /* cyb_resume */
3390Sstevel@tonic-gate };
3400Sstevel@tonic-gate cyc_handler_t hdlr;
3410Sstevel@tonic-gate cyc_time_t when;
3420Sstevel@tonic-gate
3438048SMadhavan.Venkataraman@Sun.COM mutex_init(&cbe_xcall_lock, NULL, MUTEX_DEFAULT, NULL);
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate mutex_enter(&cpu_lock);
3467039Smrj cyclic_init(&cbe, cbe_timer_resolution);
3470Sstevel@tonic-gate mutex_exit(&cpu_lock);
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate (void) add_avintr(NULL, CBE_HIGH_PIL, (avfunc)cbe_fire,
350916Sschwartz "cbe_fire_master", cbe_vector, 0, NULL, NULL, NULL);
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate if (psm_get_ipivect != NULL) {
3530Sstevel@tonic-gate (void) add_avintr(NULL, CBE_HIGH_PIL, (avfunc)cbe_fire,
3540Sstevel@tonic-gate "cbe_fire_slave",
3550Sstevel@tonic-gate (*psm_get_ipivect)(CBE_HIGH_PIL, PSM_INTR_IPI_HI),
356916Sschwartz 0, NULL, NULL, NULL);
3570Sstevel@tonic-gate }
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate (void) add_avsoftintr((void *)&cbe_clock_hdl, CBE_LOCK_PIL,
3600Sstevel@tonic-gate (avfunc)cbe_softclock, "softclock", NULL, NULL);
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate (void) add_avsoftintr((void *)&cbe_low_hdl, CBE_LOW_PIL,
3630Sstevel@tonic-gate (avfunc)cbe_low_level, "low level", NULL, NULL);
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate mutex_enter(&cpu_lock);
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate hdlr.cyh_level = CY_HIGH_LEVEL;
3680Sstevel@tonic-gate hdlr.cyh_func = (cyc_func_t)cbe_hres_tick;
3690Sstevel@tonic-gate hdlr.cyh_arg = NULL;
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate when.cyt_when = 0;
3720Sstevel@tonic-gate when.cyt_interval = nsec_per_tick;
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate cbe_hres_cyclic = cyclic_add(&hdlr, &when);
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate if (psm_post_cyclic_setup != NULL)
3770Sstevel@tonic-gate (*psm_post_cyclic_setup)(NULL);
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate mutex_exit(&cpu_lock);
3800Sstevel@tonic-gate }
381