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*11455SJonathan.Haslam@Sun.COM * Copyright 2010 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 507728SKuriakose.Kuruvilla@Sun.COM /* Do threads share performance monitoring hardware? */ 517728SKuriakose.Kuruvilla@Sun.COM static int strands_perfmon_shared = 0; 527728SKuriakose.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 */ 92*11455SJonathan.Haslam@Sun.COM if (kcpc_cpuctx || dtrace_cpc_in_use) 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 1127728SKuriakose.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; 1177728SKuriakose.Kuruvilla@Sun.COM uint32_t versionid; 1187728SKuriakose.Kuruvilla@Sun.COM struct cpuid_regs cpuid; 1190Sstevel@tonic-gate 1207728SKuriakose.Kuruvilla@Sun.COM strands_perfmon_shared = 0; 1210Sstevel@tonic-gate if (x86_feature & X86_HTT) { 1227728SKuriakose.Kuruvilla@Sun.COM if (cpuid_getvendor(cpu[0]) == X86_VENDOR_Intel) { 1237728SKuriakose.Kuruvilla@Sun.COM /* 1247728SKuriakose.Kuruvilla@Sun.COM * Intel processors that support Architectural 1257728SKuriakose.Kuruvilla@Sun.COM * Performance Monitoring Version 3 have per strand 1267728SKuriakose.Kuruvilla@Sun.COM * performance monitoring hardware. 1277728SKuriakose.Kuruvilla@Sun.COM * Hence we can allow use of performance counters on 1287728SKuriakose.Kuruvilla@Sun.COM * multiple strands on the same core simultaneously. 1297728SKuriakose.Kuruvilla@Sun.COM */ 1307728SKuriakose.Kuruvilla@Sun.COM cpuid.cp_eax = 0x0; 1317728SKuriakose.Kuruvilla@Sun.COM (void) __cpuid_insn(&cpuid); 1327728SKuriakose.Kuruvilla@Sun.COM if (cpuid.cp_eax < 0xa) { 1337728SKuriakose.Kuruvilla@Sun.COM strands_perfmon_shared = 1; 1347728SKuriakose.Kuruvilla@Sun.COM } else { 1357728SKuriakose.Kuruvilla@Sun.COM cpuid.cp_eax = 0xa; 1367728SKuriakose.Kuruvilla@Sun.COM (void) __cpuid_insn(&cpuid); 1377728SKuriakose.Kuruvilla@Sun.COM 1387728SKuriakose.Kuruvilla@Sun.COM versionid = cpuid.cp_eax & 0xFF; 1397728SKuriakose.Kuruvilla@Sun.COM if (versionid < 3) { 1407728SKuriakose.Kuruvilla@Sun.COM strands_perfmon_shared = 1; 1417728SKuriakose.Kuruvilla@Sun.COM } 1427728SKuriakose.Kuruvilla@Sun.COM } 1437728SKuriakose.Kuruvilla@Sun.COM } else { 1447728SKuriakose.Kuruvilla@Sun.COM strands_perfmon_shared = 1; 1457728SKuriakose.Kuruvilla@Sun.COM } 1467728SKuriakose.Kuruvilla@Sun.COM } 1477728SKuriakose.Kuruvilla@Sun.COM 1487728SKuriakose.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 /* 1920Sstevel@tonic-gate * Called by the generic framework to check if it's OK to bind a set to a CPU. 1930Sstevel@tonic-gate */ 1940Sstevel@tonic-gate int 1950Sstevel@tonic-gate kcpc_hw_cpu_hook(processorid_t cpuid, ulong_t *kcpc_cpumap) 1960Sstevel@tonic-gate { 1973434Sesaxe cpu_t *cpu, *p; 1983434Sesaxe pg_t *chip_pg; 1993434Sesaxe pg_cpu_itr_t itr; 2000Sstevel@tonic-gate 2017728SKuriakose.Kuruvilla@Sun.COM if (!strands_perfmon_shared) 2020Sstevel@tonic-gate return (0); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate /* 2050Sstevel@tonic-gate * Only one logical CPU on each Pentium 4 HT CPU may be bound to at 2060Sstevel@tonic-gate * once. 2070Sstevel@tonic-gate * 2080Sstevel@tonic-gate * This loop is protected by holding cpu_lock, in order to properly 2093434Sesaxe * access the cpu_t of the desired cpu. 2100Sstevel@tonic-gate */ 2110Sstevel@tonic-gate mutex_enter(&cpu_lock); 2120Sstevel@tonic-gate if ((cpu = cpu_get(cpuid)) == NULL) { 2130Sstevel@tonic-gate mutex_exit(&cpu_lock); 2140Sstevel@tonic-gate return (-1); 2150Sstevel@tonic-gate } 2160Sstevel@tonic-gate 2173434Sesaxe chip_pg = (pg_t *)pghw_find_pg(cpu, PGHW_CHIP); 2183434Sesaxe 2193434Sesaxe PG_CPU_ITR_INIT(chip_pg, itr); 2203434Sesaxe while ((p = pg_cpu_next(&itr)) != NULL) { 2213434Sesaxe if (p == cpu) 2223434Sesaxe continue; 2230Sstevel@tonic-gate if (BT_TEST(kcpc_cpumap, p->cpu_id)) { 2240Sstevel@tonic-gate mutex_exit(&cpu_lock); 2250Sstevel@tonic-gate return (-1); 2260Sstevel@tonic-gate } 2270Sstevel@tonic-gate } 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate mutex_exit(&cpu_lock); 2300Sstevel@tonic-gate return (0); 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate /* 2340Sstevel@tonic-gate * Called by the generic framework to check if it's OK to bind a set to an LWP. 2350Sstevel@tonic-gate */ 2360Sstevel@tonic-gate int 2370Sstevel@tonic-gate kcpc_hw_lwp_hook(void) 2380Sstevel@tonic-gate { 2393434Sesaxe pg_cmt_t *chip; 2403434Sesaxe group_t *chips; 2413434Sesaxe group_iter_t i; 2420Sstevel@tonic-gate 2437728SKuriakose.Kuruvilla@Sun.COM if (!strands_perfmon_shared) 2440Sstevel@tonic-gate return (0); 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate /* 2470Sstevel@tonic-gate * Only one CPU per chip may be online. 2480Sstevel@tonic-gate */ 2490Sstevel@tonic-gate mutex_enter(&cpu_lock); 2503434Sesaxe 2513434Sesaxe chips = pghw_set_lookup(PGHW_CHIP); 2523434Sesaxe if (chips == NULL) { 2533434Sesaxe mutex_exit(&cpu_lock); 2543434Sesaxe return (0); 2553434Sesaxe } 2563434Sesaxe 2573434Sesaxe group_iter_init(&i); 2583434Sesaxe while ((chip = group_iterate(chips, &i)) != NULL) { 2593434Sesaxe if (GROUP_SIZE(&chip->cmt_cpus_actv) > 1) { 2600Sstevel@tonic-gate mutex_exit(&cpu_lock); 2610Sstevel@tonic-gate return (-1); 2620Sstevel@tonic-gate } 2633434Sesaxe } 2643434Sesaxe 2650Sstevel@tonic-gate mutex_exit(&cpu_lock); 2660Sstevel@tonic-gate return (0); 2670Sstevel@tonic-gate } 268