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 53434Sesaxe * Common Development and Distribution License (the "License"). 63434Sesaxe * 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 /* 223434Sesaxe * Copyright 2007 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 /* 290Sstevel@tonic-gate * x86-specific routines used by the CPU Performance counter driver. 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/time.h> 340Sstevel@tonic-gate #include <sys/atomic.h> 350Sstevel@tonic-gate #include <sys/regset.h> 360Sstevel@tonic-gate #include <sys/privregs.h> 370Sstevel@tonic-gate #include <sys/x86_archext.h> 380Sstevel@tonic-gate #include <sys/cpuvar.h> 390Sstevel@tonic-gate #include <sys/machcpuvar.h> 400Sstevel@tonic-gate #include <sys/archsystm.h> 410Sstevel@tonic-gate #include <sys/cpc_pcbe.h> 420Sstevel@tonic-gate #include <sys/cpc_impl.h> 430Sstevel@tonic-gate #include <sys/x_call.h> 440Sstevel@tonic-gate #include <sys/cmn_err.h> 453434Sesaxe #include <sys/cmt.h> 460Sstevel@tonic-gate #include <sys/spl.h> 47*3446Smrj #include <sys/apic.h> 480Sstevel@tonic-gate 490Sstevel@tonic-gate static const uint64_t allstopped = 0; 500Sstevel@tonic-gate static kcpc_ctx_t *(*overflow_intr_handler)(caddr_t); 510Sstevel@tonic-gate 520Sstevel@tonic-gate int kcpc_hw_overflow_intr_installed; /* set by APIC code */ 530Sstevel@tonic-gate extern kcpc_ctx_t *kcpc_overflow_intr(caddr_t arg, uint64_t bitmap); 540Sstevel@tonic-gate 550Sstevel@tonic-gate extern int kcpc_counts_include_idle; /* Project Private /etc/system variable */ 560Sstevel@tonic-gate 570Sstevel@tonic-gate void (*kcpc_hw_enable_cpc_intr)(void); /* set by APIC code */ 580Sstevel@tonic-gate 590Sstevel@tonic-gate int 600Sstevel@tonic-gate kcpc_hw_add_ovf_intr(kcpc_ctx_t *(*handler)(caddr_t)) 610Sstevel@tonic-gate { 620Sstevel@tonic-gate if (x86_type != X86_TYPE_P6) 630Sstevel@tonic-gate return (0); 640Sstevel@tonic-gate overflow_intr_handler = handler; 650Sstevel@tonic-gate return (ipltospl(APIC_PCINT_IPL)); 660Sstevel@tonic-gate } 670Sstevel@tonic-gate 680Sstevel@tonic-gate void 690Sstevel@tonic-gate kcpc_hw_rem_ovf_intr(void) 700Sstevel@tonic-gate { 710Sstevel@tonic-gate overflow_intr_handler = NULL; 720Sstevel@tonic-gate } 730Sstevel@tonic-gate 740Sstevel@tonic-gate /* 750Sstevel@tonic-gate * Hook used on P4 systems to catch online/offline events. 760Sstevel@tonic-gate */ 770Sstevel@tonic-gate /*ARGSUSED*/ 780Sstevel@tonic-gate static int 790Sstevel@tonic-gate kcpc_cpu_setup(cpu_setup_t what, int cpuid, void *arg) 800Sstevel@tonic-gate { 813434Sesaxe pg_cmt_t *chip_pg; 823434Sesaxe int active_cpus_cnt; 830Sstevel@tonic-gate 840Sstevel@tonic-gate if (what != CPU_ON) 850Sstevel@tonic-gate return (0); 860Sstevel@tonic-gate 870Sstevel@tonic-gate /* 880Sstevel@tonic-gate * If any CPU-bound contexts exist, we don't need to invalidate 890Sstevel@tonic-gate * anything, as no per-LWP contexts can coexist. 900Sstevel@tonic-gate */ 910Sstevel@tonic-gate if (kcpc_cpuctx) 920Sstevel@tonic-gate return (0); 930Sstevel@tonic-gate 940Sstevel@tonic-gate /* 950Sstevel@tonic-gate * If this chip now has more than 1 active cpu, we must invalidate all 960Sstevel@tonic-gate * contexts in the system. 970Sstevel@tonic-gate */ 983434Sesaxe chip_pg = (pg_cmt_t *)pghw_find_pg(cpu[cpuid], PGHW_CHIP); 993434Sesaxe if (chip_pg != NULL) { 1003434Sesaxe active_cpus_cnt = GROUP_SIZE(&chip_pg->cmt_cpus_actv); 1013434Sesaxe if (active_cpus_cnt > 1) 1023434Sesaxe kcpc_invalidate_all(); 1033434Sesaxe } 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate return (0); 1060Sstevel@tonic-gate } 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate static kmutex_t cpu_setup_lock; /* protects setup_registered */ 1090Sstevel@tonic-gate static int setup_registered; 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate void 1120Sstevel@tonic-gate kcpc_hw_init(cpu_t *cp) 1130Sstevel@tonic-gate { 114*3446Smrj kthread_t *t = cp->cpu_idle_thread; 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate if (x86_feature & X86_HTT) { 1170Sstevel@tonic-gate mutex_enter(&cpu_setup_lock); 1180Sstevel@tonic-gate if (setup_registered == 0) { 1190Sstevel@tonic-gate mutex_enter(&cpu_lock); 1200Sstevel@tonic-gate register_cpu_setup_func(kcpc_cpu_setup, NULL); 1210Sstevel@tonic-gate mutex_exit(&cpu_lock); 1220Sstevel@tonic-gate setup_registered = 1; 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate mutex_exit(&cpu_setup_lock); 1250Sstevel@tonic-gate } 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate mutex_init(&cp->cpu_cpc_ctxlock, "cpu_cpc_ctxlock", MUTEX_DEFAULT, 0); 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate if (kcpc_counts_include_idle) 1300Sstevel@tonic-gate return; 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate installctx(t, cp, kcpc_idle_save, kcpc_idle_restore, 1330Sstevel@tonic-gate NULL, NULL, NULL, NULL); 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate 136*3446Smrj void 137*3446Smrj kcpc_hw_fini(cpu_t *cp) 138*3446Smrj { 139*3446Smrj ASSERT(cp->cpu_idle_thread == NULL); 140*3446Smrj 141*3446Smrj mutex_destroy(&cp->cpu_cpc_ctxlock); 142*3446Smrj } 143*3446Smrj 1440Sstevel@tonic-gate #define BITS(v, u, l) \ 1450Sstevel@tonic-gate (((v) >> (l)) & ((1 << (1 + (u) - (l))) - 1)) 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate #define PCBE_NAMELEN 30 /* Enough Room for pcbe.manuf.model.family.stepping */ 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate /* 1500Sstevel@tonic-gate * Examine the processor and load an appropriate PCBE. 1510Sstevel@tonic-gate */ 1520Sstevel@tonic-gate int 1530Sstevel@tonic-gate kcpc_hw_load_pcbe(void) 1540Sstevel@tonic-gate { 1550Sstevel@tonic-gate return (kcpc_pcbe_tryload(cpuid_getvendorstr(CPU), cpuid_getfamily(CPU), 1560Sstevel@tonic-gate cpuid_getmodel(CPU), cpuid_getstep(CPU))); 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate static int 1600Sstevel@tonic-gate kcpc_remotestop_func(void) 1610Sstevel@tonic-gate { 1620Sstevel@tonic-gate ASSERT(CPU->cpu_cpc_ctx != NULL); 1630Sstevel@tonic-gate pcbe_ops->pcbe_allstop(); 1640Sstevel@tonic-gate atomic_or_uint(&CPU->cpu_cpc_ctx->kc_flags, KCPC_CTX_INVALID_STOPPED); 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate return (0); 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate /* 1700Sstevel@tonic-gate * Ensure the counters are stopped on the given processor. 1710Sstevel@tonic-gate * 1720Sstevel@tonic-gate * Callers must ensure kernel preemption is disabled. 1730Sstevel@tonic-gate */ 1740Sstevel@tonic-gate void 1750Sstevel@tonic-gate kcpc_remote_stop(cpu_t *cp) 1760Sstevel@tonic-gate { 1770Sstevel@tonic-gate cpuset_t set; 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate CPUSET_ZERO(set); 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate CPUSET_ADD(set, cp->cpu_id); 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate xc_sync(0, 0, 0, X_CALL_HIPRI, set, (xc_func_t)kcpc_remotestop_func); 1840Sstevel@tonic-gate } 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate /* 1870Sstevel@tonic-gate * Called by the generic framework to check if it's OK to bind a set to a CPU. 1880Sstevel@tonic-gate */ 1890Sstevel@tonic-gate int 1900Sstevel@tonic-gate kcpc_hw_cpu_hook(processorid_t cpuid, ulong_t *kcpc_cpumap) 1910Sstevel@tonic-gate { 1923434Sesaxe cpu_t *cpu, *p; 1933434Sesaxe pg_t *chip_pg; 1943434Sesaxe pg_cpu_itr_t itr; 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate if ((x86_feature & X86_HTT) == 0) 1970Sstevel@tonic-gate return (0); 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate /* 2000Sstevel@tonic-gate * Only one logical CPU on each Pentium 4 HT CPU may be bound to at 2010Sstevel@tonic-gate * once. 2020Sstevel@tonic-gate * 2030Sstevel@tonic-gate * This loop is protected by holding cpu_lock, in order to properly 2043434Sesaxe * access the cpu_t of the desired cpu. 2050Sstevel@tonic-gate */ 2060Sstevel@tonic-gate mutex_enter(&cpu_lock); 2070Sstevel@tonic-gate if ((cpu = cpu_get(cpuid)) == NULL) { 2080Sstevel@tonic-gate mutex_exit(&cpu_lock); 2090Sstevel@tonic-gate return (-1); 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate 2123434Sesaxe chip_pg = (pg_t *)pghw_find_pg(cpu, PGHW_CHIP); 2133434Sesaxe 2143434Sesaxe PG_CPU_ITR_INIT(chip_pg, itr); 2153434Sesaxe while ((p = pg_cpu_next(&itr)) != NULL) { 2163434Sesaxe if (p == cpu) 2173434Sesaxe continue; 2180Sstevel@tonic-gate if (BT_TEST(kcpc_cpumap, p->cpu_id)) { 2190Sstevel@tonic-gate mutex_exit(&cpu_lock); 2200Sstevel@tonic-gate return (-1); 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate mutex_exit(&cpu_lock); 2250Sstevel@tonic-gate return (0); 2260Sstevel@tonic-gate } 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate /* 2290Sstevel@tonic-gate * Called by the generic framework to check if it's OK to bind a set to an LWP. 2300Sstevel@tonic-gate */ 2310Sstevel@tonic-gate int 2320Sstevel@tonic-gate kcpc_hw_lwp_hook(void) 2330Sstevel@tonic-gate { 2343434Sesaxe pg_cmt_t *chip; 2353434Sesaxe group_t *chips; 2363434Sesaxe group_iter_t i; 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate if ((x86_feature & X86_HTT) == 0) 2390Sstevel@tonic-gate return (0); 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate /* 2420Sstevel@tonic-gate * Only one CPU per chip may be online. 2430Sstevel@tonic-gate */ 2440Sstevel@tonic-gate mutex_enter(&cpu_lock); 2453434Sesaxe 2463434Sesaxe chips = pghw_set_lookup(PGHW_CHIP); 2473434Sesaxe if (chips == NULL) { 2483434Sesaxe mutex_exit(&cpu_lock); 2493434Sesaxe return (0); 2503434Sesaxe } 2513434Sesaxe 2523434Sesaxe group_iter_init(&i); 2533434Sesaxe while ((chip = group_iterate(chips, &i)) != NULL) { 2543434Sesaxe if (GROUP_SIZE(&chip->cmt_cpus_actv) > 1) { 2550Sstevel@tonic-gate mutex_exit(&cpu_lock); 2560Sstevel@tonic-gate return (-1); 2570Sstevel@tonic-gate } 2583434Sesaxe } 2593434Sesaxe 2600Sstevel@tonic-gate mutex_exit(&cpu_lock); 2610Sstevel@tonic-gate return (0); 2620Sstevel@tonic-gate } 263