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 /* 22*7728SKuriakose.Kuruvilla@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * x86-specific routines used by the CPU Performance counter driver. 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <sys/types.h> 310Sstevel@tonic-gate #include <sys/time.h> 320Sstevel@tonic-gate #include <sys/atomic.h> 330Sstevel@tonic-gate #include <sys/regset.h> 340Sstevel@tonic-gate #include <sys/privregs.h> 350Sstevel@tonic-gate #include <sys/x86_archext.h> 360Sstevel@tonic-gate #include <sys/cpuvar.h> 370Sstevel@tonic-gate #include <sys/machcpuvar.h> 380Sstevel@tonic-gate #include <sys/archsystm.h> 390Sstevel@tonic-gate #include <sys/cpc_pcbe.h> 400Sstevel@tonic-gate #include <sys/cpc_impl.h> 410Sstevel@tonic-gate #include <sys/x_call.h> 420Sstevel@tonic-gate #include <sys/cmn_err.h> 433434Sesaxe #include <sys/cmt.h> 440Sstevel@tonic-gate #include <sys/spl.h> 453446Smrj #include <sys/apic.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate static const uint64_t allstopped = 0; 480Sstevel@tonic-gate static kcpc_ctx_t *(*overflow_intr_handler)(caddr_t); 490Sstevel@tonic-gate 50*7728SKuriakose.Kuruvilla@Sun.COM /* Do threads share performance monitoring hardware? */ 51*7728SKuriakose.Kuruvilla@Sun.COM static int strands_perfmon_shared = 0; 52*7728SKuriakose.Kuruvilla@Sun.COM 530Sstevel@tonic-gate int kcpc_hw_overflow_intr_installed; /* set by APIC code */ 540Sstevel@tonic-gate extern kcpc_ctx_t *kcpc_overflow_intr(caddr_t arg, uint64_t bitmap); 550Sstevel@tonic-gate 560Sstevel@tonic-gate extern int kcpc_counts_include_idle; /* Project Private /etc/system variable */ 570Sstevel@tonic-gate 580Sstevel@tonic-gate void (*kcpc_hw_enable_cpc_intr)(void); /* set by APIC code */ 590Sstevel@tonic-gate 600Sstevel@tonic-gate int 610Sstevel@tonic-gate kcpc_hw_add_ovf_intr(kcpc_ctx_t *(*handler)(caddr_t)) 620Sstevel@tonic-gate { 630Sstevel@tonic-gate if (x86_type != X86_TYPE_P6) 640Sstevel@tonic-gate return (0); 650Sstevel@tonic-gate overflow_intr_handler = handler; 660Sstevel@tonic-gate return (ipltospl(APIC_PCINT_IPL)); 670Sstevel@tonic-gate } 680Sstevel@tonic-gate 690Sstevel@tonic-gate void 700Sstevel@tonic-gate kcpc_hw_rem_ovf_intr(void) 710Sstevel@tonic-gate { 720Sstevel@tonic-gate overflow_intr_handler = NULL; 730Sstevel@tonic-gate } 740Sstevel@tonic-gate 750Sstevel@tonic-gate /* 760Sstevel@tonic-gate * Hook used on P4 systems to catch online/offline events. 770Sstevel@tonic-gate */ 780Sstevel@tonic-gate /*ARGSUSED*/ 790Sstevel@tonic-gate static int 800Sstevel@tonic-gate kcpc_cpu_setup(cpu_setup_t what, int cpuid, void *arg) 810Sstevel@tonic-gate { 823434Sesaxe pg_cmt_t *chip_pg; 833434Sesaxe int active_cpus_cnt; 840Sstevel@tonic-gate 850Sstevel@tonic-gate if (what != CPU_ON) 860Sstevel@tonic-gate return (0); 870Sstevel@tonic-gate 880Sstevel@tonic-gate /* 890Sstevel@tonic-gate * If any CPU-bound contexts exist, we don't need to invalidate 900Sstevel@tonic-gate * anything, as no per-LWP contexts can coexist. 910Sstevel@tonic-gate */ 920Sstevel@tonic-gate if (kcpc_cpuctx) 930Sstevel@tonic-gate return (0); 940Sstevel@tonic-gate 950Sstevel@tonic-gate /* 960Sstevel@tonic-gate * If this chip now has more than 1 active cpu, we must invalidate all 970Sstevel@tonic-gate * contexts in the system. 980Sstevel@tonic-gate */ 993434Sesaxe chip_pg = (pg_cmt_t *)pghw_find_pg(cpu[cpuid], PGHW_CHIP); 1003434Sesaxe if (chip_pg != NULL) { 1013434Sesaxe active_cpus_cnt = GROUP_SIZE(&chip_pg->cmt_cpus_actv); 1023434Sesaxe if (active_cpus_cnt > 1) 1033434Sesaxe kcpc_invalidate_all(); 1043434Sesaxe } 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate return (0); 1070Sstevel@tonic-gate } 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate static kmutex_t cpu_setup_lock; /* protects setup_registered */ 1100Sstevel@tonic-gate static int setup_registered; 1110Sstevel@tonic-gate 112*7728SKuriakose.Kuruvilla@Sun.COM 1130Sstevel@tonic-gate void 1140Sstevel@tonic-gate kcpc_hw_init(cpu_t *cp) 1150Sstevel@tonic-gate { 1163446Smrj kthread_t *t = cp->cpu_idle_thread; 117*7728SKuriakose.Kuruvilla@Sun.COM uint32_t versionid; 118*7728SKuriakose.Kuruvilla@Sun.COM struct cpuid_regs cpuid; 1190Sstevel@tonic-gate 120*7728SKuriakose.Kuruvilla@Sun.COM strands_perfmon_shared = 0; 1210Sstevel@tonic-gate if (x86_feature & X86_HTT) { 122*7728SKuriakose.Kuruvilla@Sun.COM if (cpuid_getvendor(cpu[0]) == X86_VENDOR_Intel) { 123*7728SKuriakose.Kuruvilla@Sun.COM /* 124*7728SKuriakose.Kuruvilla@Sun.COM * Intel processors that support Architectural 125*7728SKuriakose.Kuruvilla@Sun.COM * Performance Monitoring Version 3 have per strand 126*7728SKuriakose.Kuruvilla@Sun.COM * performance monitoring hardware. 127*7728SKuriakose.Kuruvilla@Sun.COM * Hence we can allow use of performance counters on 128*7728SKuriakose.Kuruvilla@Sun.COM * multiple strands on the same core simultaneously. 129*7728SKuriakose.Kuruvilla@Sun.COM */ 130*7728SKuriakose.Kuruvilla@Sun.COM cpuid.cp_eax = 0x0; 131*7728SKuriakose.Kuruvilla@Sun.COM (void) __cpuid_insn(&cpuid); 132*7728SKuriakose.Kuruvilla@Sun.COM if (cpuid.cp_eax < 0xa) { 133*7728SKuriakose.Kuruvilla@Sun.COM strands_perfmon_shared = 1; 134*7728SKuriakose.Kuruvilla@Sun.COM } else { 135*7728SKuriakose.Kuruvilla@Sun.COM cpuid.cp_eax = 0xa; 136*7728SKuriakose.Kuruvilla@Sun.COM (void) __cpuid_insn(&cpuid); 137*7728SKuriakose.Kuruvilla@Sun.COM 138*7728SKuriakose.Kuruvilla@Sun.COM versionid = cpuid.cp_eax & 0xFF; 139*7728SKuriakose.Kuruvilla@Sun.COM if (versionid < 3) { 140*7728SKuriakose.Kuruvilla@Sun.COM strands_perfmon_shared = 1; 141*7728SKuriakose.Kuruvilla@Sun.COM } 142*7728SKuriakose.Kuruvilla@Sun.COM } 143*7728SKuriakose.Kuruvilla@Sun.COM } else { 144*7728SKuriakose.Kuruvilla@Sun.COM strands_perfmon_shared = 1; 145*7728SKuriakose.Kuruvilla@Sun.COM } 146*7728SKuriakose.Kuruvilla@Sun.COM } 147*7728SKuriakose.Kuruvilla@Sun.COM 148*7728SKuriakose.Kuruvilla@Sun.COM if (strands_perfmon_shared) { 1490Sstevel@tonic-gate mutex_enter(&cpu_setup_lock); 1500Sstevel@tonic-gate if (setup_registered == 0) { 1510Sstevel@tonic-gate mutex_enter(&cpu_lock); 1520Sstevel@tonic-gate register_cpu_setup_func(kcpc_cpu_setup, NULL); 1530Sstevel@tonic-gate mutex_exit(&cpu_lock); 1540Sstevel@tonic-gate setup_registered = 1; 1550Sstevel@tonic-gate } 1560Sstevel@tonic-gate mutex_exit(&cpu_setup_lock); 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate mutex_init(&cp->cpu_cpc_ctxlock, "cpu_cpc_ctxlock", MUTEX_DEFAULT, 0); 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate if (kcpc_counts_include_idle) 1620Sstevel@tonic-gate return; 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate installctx(t, cp, kcpc_idle_save, kcpc_idle_restore, 1650Sstevel@tonic-gate NULL, NULL, NULL, NULL); 1660Sstevel@tonic-gate } 1670Sstevel@tonic-gate 1683446Smrj void 1693446Smrj kcpc_hw_fini(cpu_t *cp) 1703446Smrj { 1713446Smrj ASSERT(cp->cpu_idle_thread == NULL); 1723446Smrj 1733446Smrj mutex_destroy(&cp->cpu_cpc_ctxlock); 1743446Smrj } 1753446Smrj 1760Sstevel@tonic-gate #define BITS(v, u, l) \ 1770Sstevel@tonic-gate (((v) >> (l)) & ((1 << (1 + (u) - (l))) - 1)) 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate #define PCBE_NAMELEN 30 /* Enough Room for pcbe.manuf.model.family.stepping */ 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate /* 1820Sstevel@tonic-gate * Examine the processor and load an appropriate PCBE. 1830Sstevel@tonic-gate */ 1840Sstevel@tonic-gate int 1850Sstevel@tonic-gate kcpc_hw_load_pcbe(void) 1860Sstevel@tonic-gate { 1870Sstevel@tonic-gate return (kcpc_pcbe_tryload(cpuid_getvendorstr(CPU), cpuid_getfamily(CPU), 1880Sstevel@tonic-gate cpuid_getmodel(CPU), cpuid_getstep(CPU))); 1890Sstevel@tonic-gate } 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate static int 1920Sstevel@tonic-gate kcpc_remotestop_func(void) 1930Sstevel@tonic-gate { 1940Sstevel@tonic-gate ASSERT(CPU->cpu_cpc_ctx != NULL); 1950Sstevel@tonic-gate pcbe_ops->pcbe_allstop(); 1960Sstevel@tonic-gate atomic_or_uint(&CPU->cpu_cpc_ctx->kc_flags, KCPC_CTX_INVALID_STOPPED); 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate return (0); 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate /* 2020Sstevel@tonic-gate * Ensure the counters are stopped on the given processor. 2030Sstevel@tonic-gate * 2040Sstevel@tonic-gate * Callers must ensure kernel preemption is disabled. 2050Sstevel@tonic-gate */ 2060Sstevel@tonic-gate void 2070Sstevel@tonic-gate kcpc_remote_stop(cpu_t *cp) 2080Sstevel@tonic-gate { 2090Sstevel@tonic-gate cpuset_t set; 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate CPUSET_ZERO(set); 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate CPUSET_ADD(set, cp->cpu_id); 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate xc_sync(0, 0, 0, X_CALL_HIPRI, set, (xc_func_t)kcpc_remotestop_func); 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate /* 2190Sstevel@tonic-gate * Called by the generic framework to check if it's OK to bind a set to a CPU. 2200Sstevel@tonic-gate */ 2210Sstevel@tonic-gate int 2220Sstevel@tonic-gate kcpc_hw_cpu_hook(processorid_t cpuid, ulong_t *kcpc_cpumap) 2230Sstevel@tonic-gate { 2243434Sesaxe cpu_t *cpu, *p; 2253434Sesaxe pg_t *chip_pg; 2263434Sesaxe pg_cpu_itr_t itr; 2270Sstevel@tonic-gate 228*7728SKuriakose.Kuruvilla@Sun.COM if (!strands_perfmon_shared) 2290Sstevel@tonic-gate return (0); 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate /* 2320Sstevel@tonic-gate * Only one logical CPU on each Pentium 4 HT CPU may be bound to at 2330Sstevel@tonic-gate * once. 2340Sstevel@tonic-gate * 2350Sstevel@tonic-gate * This loop is protected by holding cpu_lock, in order to properly 2363434Sesaxe * access the cpu_t of the desired cpu. 2370Sstevel@tonic-gate */ 2380Sstevel@tonic-gate mutex_enter(&cpu_lock); 2390Sstevel@tonic-gate if ((cpu = cpu_get(cpuid)) == NULL) { 2400Sstevel@tonic-gate mutex_exit(&cpu_lock); 2410Sstevel@tonic-gate return (-1); 2420Sstevel@tonic-gate } 2430Sstevel@tonic-gate 2443434Sesaxe chip_pg = (pg_t *)pghw_find_pg(cpu, PGHW_CHIP); 2453434Sesaxe 2463434Sesaxe PG_CPU_ITR_INIT(chip_pg, itr); 2473434Sesaxe while ((p = pg_cpu_next(&itr)) != NULL) { 2483434Sesaxe if (p == cpu) 2493434Sesaxe continue; 2500Sstevel@tonic-gate if (BT_TEST(kcpc_cpumap, p->cpu_id)) { 2510Sstevel@tonic-gate mutex_exit(&cpu_lock); 2520Sstevel@tonic-gate return (-1); 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate } 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate mutex_exit(&cpu_lock); 2570Sstevel@tonic-gate return (0); 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate /* 2610Sstevel@tonic-gate * Called by the generic framework to check if it's OK to bind a set to an LWP. 2620Sstevel@tonic-gate */ 2630Sstevel@tonic-gate int 2640Sstevel@tonic-gate kcpc_hw_lwp_hook(void) 2650Sstevel@tonic-gate { 2663434Sesaxe pg_cmt_t *chip; 2673434Sesaxe group_t *chips; 2683434Sesaxe group_iter_t i; 2690Sstevel@tonic-gate 270*7728SKuriakose.Kuruvilla@Sun.COM if (!strands_perfmon_shared) 2710Sstevel@tonic-gate return (0); 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate /* 2740Sstevel@tonic-gate * Only one CPU per chip may be online. 2750Sstevel@tonic-gate */ 2760Sstevel@tonic-gate mutex_enter(&cpu_lock); 2773434Sesaxe 2783434Sesaxe chips = pghw_set_lookup(PGHW_CHIP); 2793434Sesaxe if (chips == NULL) { 2803434Sesaxe mutex_exit(&cpu_lock); 2813434Sesaxe return (0); 2823434Sesaxe } 2833434Sesaxe 2843434Sesaxe group_iter_init(&i); 2853434Sesaxe while ((chip = group_iterate(chips, &i)) != NULL) { 2863434Sesaxe if (GROUP_SIZE(&chip->cmt_cpus_actv) > 1) { 2870Sstevel@tonic-gate mutex_exit(&cpu_lock); 2880Sstevel@tonic-gate return (-1); 2890Sstevel@tonic-gate } 2903434Sesaxe } 2913434Sesaxe 2920Sstevel@tonic-gate mutex_exit(&cpu_lock); 2930Sstevel@tonic-gate return (0); 2940Sstevel@tonic-gate } 295