17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5fb2f18f8Sesaxe * Common Development and Distribution License (the "License"). 6fb2f18f8Sesaxe * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*7417cfdeSKuriakose Kuruvilla * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 25c7a079a8SJonathan Haslam /* 26c7a079a8SJonathan Haslam * This file contains preset event names from the Performance Application 27c7a079a8SJonathan Haslam * Programming Interface v3.5 which included the following notice: 28c7a079a8SJonathan Haslam * 29c7a079a8SJonathan Haslam * Copyright (c) 2005,6 30c7a079a8SJonathan Haslam * Innovative Computing Labs 31c7a079a8SJonathan Haslam * Computer Science Department, 32c7a079a8SJonathan Haslam * University of Tennessee, 33c7a079a8SJonathan Haslam * Knoxville, TN. 34c7a079a8SJonathan Haslam * All Rights Reserved. 35c7a079a8SJonathan Haslam * 36c7a079a8SJonathan Haslam * 37c7a079a8SJonathan Haslam * Redistribution and use in source and binary forms, with or without 38c7a079a8SJonathan Haslam * modification, are permitted provided that the following conditions are met: 39c7a079a8SJonathan Haslam * 40c7a079a8SJonathan Haslam * * Redistributions of source code must retain the above copyright notice, 41c7a079a8SJonathan Haslam * this list of conditions and the following disclaimer. 42c7a079a8SJonathan Haslam * * Redistributions in binary form must reproduce the above copyright 43c7a079a8SJonathan Haslam * notice, this list of conditions and the following disclaimer in the 44c7a079a8SJonathan Haslam * documentation and/or other materials provided with the distribution. 45c7a079a8SJonathan Haslam * * Neither the name of the University of Tennessee nor the names of its 46c7a079a8SJonathan Haslam * contributors may be used to endorse or promote products derived from 47c7a079a8SJonathan Haslam * this software without specific prior written permission. 48c7a079a8SJonathan Haslam * 49c7a079a8SJonathan Haslam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 50c7a079a8SJonathan Haslam * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51c7a079a8SJonathan Haslam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52c7a079a8SJonathan Haslam * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 53c7a079a8SJonathan Haslam * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 54c7a079a8SJonathan Haslam * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 55c7a079a8SJonathan Haslam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 56c7a079a8SJonathan Haslam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 57c7a079a8SJonathan Haslam * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 58c7a079a8SJonathan Haslam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 59c7a079a8SJonathan Haslam * POSSIBILITY OF SUCH DAMAGE. 60c7a079a8SJonathan Haslam * 61c7a079a8SJonathan Haslam * 62c7a079a8SJonathan Haslam * This open source software license conforms to the BSD License template. 63c7a079a8SJonathan Haslam */ 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /* 667c478bd9Sstevel@tonic-gate * Performance Counter Back-End for Pentium 4. 677c478bd9Sstevel@tonic-gate */ 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 707c478bd9Sstevel@tonic-gate #include <sys/param.h> 717c478bd9Sstevel@tonic-gate #include <sys/cpc_impl.h> 727c478bd9Sstevel@tonic-gate #include <sys/cpc_pcbe.h> 737c478bd9Sstevel@tonic-gate #include <sys/inttypes.h> 747c478bd9Sstevel@tonic-gate #include <sys/errno.h> 757c478bd9Sstevel@tonic-gate #include <sys/systm.h> 767c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 777c478bd9Sstevel@tonic-gate #include <sys/x86_archext.h> 787c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 797c478bd9Sstevel@tonic-gate #include <sys/sdt.h> 807c478bd9Sstevel@tonic-gate #include <sys/cred.h> 817c478bd9Sstevel@tonic-gate #include <sys/policy.h> 827c478bd9Sstevel@tonic-gate #include <sys/privregs.h> 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate static int p4_pcbe_init(void); 857c478bd9Sstevel@tonic-gate static uint_t p4_pcbe_ncounters(void); 867c478bd9Sstevel@tonic-gate static const char *p4_pcbe_impl_name(void); 877c478bd9Sstevel@tonic-gate static const char *p4_pcbe_cpuref(void); 887c478bd9Sstevel@tonic-gate static char *p4_pcbe_list_events(uint_t picnum); 897c478bd9Sstevel@tonic-gate static char *p4_pcbe_list_attrs(void); 907c478bd9Sstevel@tonic-gate static uint64_t p4_pcbe_event_coverage(char *event); 917c478bd9Sstevel@tonic-gate static uint64_t p4_pcbe_overflow_bitmap(void); 927c478bd9Sstevel@tonic-gate static int p4_pcbe_configure(uint_t picnum, char *event, uint64_t preset, 937c478bd9Sstevel@tonic-gate uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data, 947c478bd9Sstevel@tonic-gate void *token); 957c478bd9Sstevel@tonic-gate static void p4_pcbe_program(void *token); 967c478bd9Sstevel@tonic-gate static void p4_pcbe_allstop(void); 977c478bd9Sstevel@tonic-gate static void p4_pcbe_sample(void *token); 987c478bd9Sstevel@tonic-gate static void p4_pcbe_free(void *config); 997c478bd9Sstevel@tonic-gate 100fb2f18f8Sesaxe extern int cpuid_get_clogid(cpu_t *); 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate static pcbe_ops_t p4_pcbe_ops = { 1037c478bd9Sstevel@tonic-gate PCBE_VER_1, 1047c478bd9Sstevel@tonic-gate CPC_CAP_OVERFLOW_INTERRUPT | CPC_CAP_OVERFLOW_PRECISE, 1057c478bd9Sstevel@tonic-gate p4_pcbe_ncounters, 1067c478bd9Sstevel@tonic-gate p4_pcbe_impl_name, 1077c478bd9Sstevel@tonic-gate p4_pcbe_cpuref, 1087c478bd9Sstevel@tonic-gate p4_pcbe_list_events, 1097c478bd9Sstevel@tonic-gate p4_pcbe_list_attrs, 1107c478bd9Sstevel@tonic-gate p4_pcbe_event_coverage, 1117c478bd9Sstevel@tonic-gate p4_pcbe_overflow_bitmap, 1127c478bd9Sstevel@tonic-gate p4_pcbe_configure, 1137c478bd9Sstevel@tonic-gate p4_pcbe_program, 1147c478bd9Sstevel@tonic-gate p4_pcbe_allstop, 1157c478bd9Sstevel@tonic-gate p4_pcbe_sample, 1167c478bd9Sstevel@tonic-gate p4_pcbe_free 1177c478bd9Sstevel@tonic-gate }; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* 1207c478bd9Sstevel@tonic-gate * P4 Configuration Flags. 1217c478bd9Sstevel@tonic-gate */ 1227c478bd9Sstevel@tonic-gate #define P4_THIS_USR 0x1 /* HTT: Measure usr events on this logical CPU */ 1237c478bd9Sstevel@tonic-gate #define P4_THIS_SYS 0x2 /* HTT: Measure os events on this logical CPU */ 1247c478bd9Sstevel@tonic-gate #define P4_SIBLING_USR 0x4 /* HTT: Measure os events on other logical CPU */ 1257c478bd9Sstevel@tonic-gate #define P4_SIBLING_SYS 0x8 /* HTT: Measure usr events on other logical CPU */ 1267c478bd9Sstevel@tonic-gate #define P4_PMI 0x10 /* HTT: Set PMI bit for local logical CPU */ 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate typedef struct _p4_pcbe_config { 1297c478bd9Sstevel@tonic-gate uint8_t p4_flags; 1307c478bd9Sstevel@tonic-gate uint8_t p4_picno; /* From 0 to 18 */ 1317c478bd9Sstevel@tonic-gate uint8_t p4_escr_ndx; /* Which ESCR to use */ 1327c478bd9Sstevel@tonic-gate uint32_t p4_escr; /* Value to program in selected ESCR */ 1337c478bd9Sstevel@tonic-gate uint32_t p4_cccr; /* Value to program in counter's CCCR */ 1347c478bd9Sstevel@tonic-gate uint64_t p4_rawpic; 1357c478bd9Sstevel@tonic-gate } p4_pcbe_config_t; 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate typedef uint32_t cntr_map_t; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate typedef struct _p4_escr { 1407c478bd9Sstevel@tonic-gate int pe_num; 1417c478bd9Sstevel@tonic-gate uint32_t pe_addr; 1427c478bd9Sstevel@tonic-gate uint32_t pe_map; /* bitmap of counters; bit 1 means ctr 0 */ 1437c478bd9Sstevel@tonic-gate } p4_escr_t; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate #define MASK40 UINT64_C(0xffffffffff) 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate /* 1487c478bd9Sstevel@tonic-gate * CCCR field definitions. 1497c478bd9Sstevel@tonic-gate * 1507c478bd9Sstevel@tonic-gate * Note that the Intel Developer's Manual states that the reserved field at 1517c478bd9Sstevel@tonic-gate * bit location 16 and 17 must be set to 11. (??) 1527c478bd9Sstevel@tonic-gate */ 1537c478bd9Sstevel@tonic-gate #define CCCR_ENABLE_SHIFT 12 1547c478bd9Sstevel@tonic-gate #define CCCR_ESCR_SEL_SHIFT 13 1557c478bd9Sstevel@tonic-gate #define CCCR_ACTV_THR_SHIFT 16 1567c478bd9Sstevel@tonic-gate #define CCCR_COMPARE_SHIFT 18 1577c478bd9Sstevel@tonic-gate #define CCCR_COMPLEMENT_SHIFT 19 1587c478bd9Sstevel@tonic-gate #define CCCR_THRESHOLD_SHIFT 20 1597c478bd9Sstevel@tonic-gate #define CCCR_EDGE_SHIFT 24 1607c478bd9Sstevel@tonic-gate #define CCCR_OVF_PMI_SHIFT 26 1617c478bd9Sstevel@tonic-gate #define CCCR_OVF_PMI_T0_SHIFT 26 1627c478bd9Sstevel@tonic-gate #define CCCR_OVF_PMI_T1_SHIFT 27 1637c478bd9Sstevel@tonic-gate #define CCCR_OVF_SHIFT 31 1647c478bd9Sstevel@tonic-gate #define CCCR_ACTV_THR_MASK 0x3 1657c478bd9Sstevel@tonic-gate #define CCCR_THRESHOLD_MAX 0xF 1667c478bd9Sstevel@tonic-gate #define CCCR_ENABLE (1U << CCCR_ENABLE_SHIFT) 1677c478bd9Sstevel@tonic-gate #define CCCR_COMPARE (1U << CCCR_COMPARE_SHIFT) 1687c478bd9Sstevel@tonic-gate #define CCCR_COMPLEMENT (1U << CCCR_COMPLEMENT_SHIFT) 1697c478bd9Sstevel@tonic-gate #define CCCR_EDGE (1U << CCCR_EDGE_SHIFT) 1707c478bd9Sstevel@tonic-gate #define CCCR_OVF_PMI (1U << CCCR_OVF_PMI_SHIFT) 1717c478bd9Sstevel@tonic-gate #define CCCR_OVF_PMI_T0 (1U << CCCR_OVF_PMI_T0_SHIFT) 1727c478bd9Sstevel@tonic-gate #define CCCR_OVF_PMI_T1 (1U << CCCR_OVF_PMI_T1_SHIFT) 1737c478bd9Sstevel@tonic-gate #define CCCR_INIT CCCR_ENABLE 1747c478bd9Sstevel@tonic-gate #define CCCR_OVF (1U << CCCR_OVF_SHIFT) 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate #define ESCR_EVSEL_SHIFT 25 1777c478bd9Sstevel@tonic-gate #define ESCR_EVMASK_SHIFT 9 1787c478bd9Sstevel@tonic-gate #define ESCR_TAG_VALUE_SHIFT 5 1797c478bd9Sstevel@tonic-gate #define ESCR_TAG_VALUE_MAX 0xF 1807c478bd9Sstevel@tonic-gate #define ESCR_TAG_ENABLE_SHIFT 4 1817c478bd9Sstevel@tonic-gate #define ESCR_USR_SHIFT 2 1827c478bd9Sstevel@tonic-gate #define ESCR_OS_SHIFT 3 1837c478bd9Sstevel@tonic-gate #define ESCR_USR (1U << ESCR_USR_SHIFT) 1847c478bd9Sstevel@tonic-gate #define ESCR_OS (1U << ESCR_OS_SHIFT) 1857c478bd9Sstevel@tonic-gate #define ESCR_TAG_ENABLE (1U << ESCR_TAG_ENABLE_SHIFT) 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* 1887c478bd9Sstevel@tonic-gate * HyperThreaded ESCR fields. 1897c478bd9Sstevel@tonic-gate */ 1907c478bd9Sstevel@tonic-gate #define ESCR_T0_OS_SHIFT 3 1917c478bd9Sstevel@tonic-gate #define ESCR_T0_USR_SHIFT 2 1927c478bd9Sstevel@tonic-gate #define ESCR_T1_OS_SHIFT 1 1937c478bd9Sstevel@tonic-gate #define ESCR_T1_USR_SHIFT 0 1947c478bd9Sstevel@tonic-gate #define ESCR_T0_OS (1U << ESCR_T0_OS_SHIFT) 1957c478bd9Sstevel@tonic-gate #define ESCR_T0_USR (1U << ESCR_T0_USR_SHIFT) 1967c478bd9Sstevel@tonic-gate #define ESCR_T1_OS (1U << ESCR_T1_OS_SHIFT) 1977c478bd9Sstevel@tonic-gate #define ESCR_T1_USR (1U << ESCR_T1_USR_SHIFT) 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * ESCRs are grouped by counter; each group of ESCRs is associated with a 2017c478bd9Sstevel@tonic-gate * distinct group of counters. Use these macros to fill in the table below. 2027c478bd9Sstevel@tonic-gate */ 2037c478bd9Sstevel@tonic-gate #define BPU0_map (0x1 | 0x2) /* Counters 0 and 1 */ 2047c478bd9Sstevel@tonic-gate #define BPU2_map (0x4 | 0x8) /* Counters 2 and 3 */ 2057c478bd9Sstevel@tonic-gate #define MS0_map (0x10 | 0x20) /* Counters 4 and 5 */ 2067c478bd9Sstevel@tonic-gate #define MS2_map (0x40 | 0x80) /* Counters 6 and 7 */ 2077c478bd9Sstevel@tonic-gate #define FLAME0_map (0x100 | 0x200) /* Counters 8 and 9 */ 2087c478bd9Sstevel@tonic-gate #define FLAME2_map (0x400 | 0x800) /* Counters 10 and 11 */ 2097c478bd9Sstevel@tonic-gate #define IQ0_map (0x1000 | 0x2000 | 0x10000) /* Counters 12, 13, 16 */ 2107c478bd9Sstevel@tonic-gate #define IQ2_map (0x4000 | 0x8000 | 0x20000) /* Counters 14, 15, 17 */ 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate /* 2137c478bd9Sstevel@tonic-gate * Table describing the 45 Event Selection and Control Registers (ESCRs). 2147c478bd9Sstevel@tonic-gate */ 2157c478bd9Sstevel@tonic-gate const p4_escr_t p4_escrs[] = { 2167c478bd9Sstevel@tonic-gate #define BPU0 (1) 2177c478bd9Sstevel@tonic-gate { 0, 0x3B2, BPU0_map }, /* 0 */ 2187c478bd9Sstevel@tonic-gate #define IS0 (1ULL << 1) 2197c478bd9Sstevel@tonic-gate { 1, 0x3B4, BPU0_map }, /* 1 */ 2207c478bd9Sstevel@tonic-gate #define MOB0 (1ULL << 2) 2217c478bd9Sstevel@tonic-gate { 2, 0x3AA, BPU0_map }, /* 2 */ 2227c478bd9Sstevel@tonic-gate #define ITLB0 (1ULL << 3) 2237c478bd9Sstevel@tonic-gate { 3, 0x3B6, BPU0_map }, /* 3 */ 2247c478bd9Sstevel@tonic-gate #define PMH0 (1ULL << 4) 2257c478bd9Sstevel@tonic-gate { 4, 0x3AC, BPU0_map }, /* 4 */ 2267c478bd9Sstevel@tonic-gate #define IX0 (1ULL << 5) 2277c478bd9Sstevel@tonic-gate { 5, 0x3C8, BPU0_map }, /* 5 */ 2287c478bd9Sstevel@tonic-gate #define FSB0 (1ULL << 6) 2297c478bd9Sstevel@tonic-gate { 6, 0x3A2, BPU0_map }, /* 6 */ 2307c478bd9Sstevel@tonic-gate #define BSU0 (1ULL << 7) 2317c478bd9Sstevel@tonic-gate { 7, 0x3A0, BPU0_map }, /* 7 */ 2327c478bd9Sstevel@tonic-gate #define BPU1 (1ULL << 8) 2337c478bd9Sstevel@tonic-gate { 0, 0x3B3, BPU2_map }, /* 8 */ 2347c478bd9Sstevel@tonic-gate #define IS1 (1ULL << 9) 2357c478bd9Sstevel@tonic-gate { 1, 0x3B5, BPU2_map }, /* 9 */ 2367c478bd9Sstevel@tonic-gate #define MOB1 (1ULL << 10) 2377c478bd9Sstevel@tonic-gate { 2, 0x3AB, BPU2_map }, /* 10 */ 2387c478bd9Sstevel@tonic-gate #define ITLB1 (1ULL << 11) 2397c478bd9Sstevel@tonic-gate { 3, 0x3B7, BPU2_map }, /* 11 */ 2407c478bd9Sstevel@tonic-gate #define PMH1 (1ULL << 12) 2417c478bd9Sstevel@tonic-gate { 4, 0x3AD, BPU2_map }, /* 12 */ 2427c478bd9Sstevel@tonic-gate #define IX1 (1ULL << 13) 2437c478bd9Sstevel@tonic-gate { 5, 0x3C9, BPU2_map }, /* 13 */ 2447c478bd9Sstevel@tonic-gate #define FSB1 (1ULL << 14) 2457c478bd9Sstevel@tonic-gate { 6, 0x3A3, BPU2_map }, /* 14 */ 2467c478bd9Sstevel@tonic-gate #define BSU1 (1ULL << 15) 2477c478bd9Sstevel@tonic-gate { 7, 0x3A1, BPU2_map }, /* 15 */ 2487c478bd9Sstevel@tonic-gate #define MS0 (1ULL << 16) 2497c478bd9Sstevel@tonic-gate { 0, 0x3C0, MS0_map }, /* 16 */ 2507c478bd9Sstevel@tonic-gate #define TC0 (1ULL << 17) 2517c478bd9Sstevel@tonic-gate { 1, 0x3C4, MS0_map }, /* 17 */ 2527c478bd9Sstevel@tonic-gate #define TBPU0 (1ULL << 18) 2537c478bd9Sstevel@tonic-gate { 2, 0x3C2, MS0_map }, /* 18 */ 2547c478bd9Sstevel@tonic-gate #define MS1 (1ULL << 19) 2557c478bd9Sstevel@tonic-gate { 0, 0x3C1, MS2_map }, /* 19 */ 2567c478bd9Sstevel@tonic-gate #define TC1 (1ULL << 20) 2577c478bd9Sstevel@tonic-gate { 1, 0x3C5, MS2_map }, /* 20 */ 2587c478bd9Sstevel@tonic-gate #define TBPU1 (1ULL << 21) 2597c478bd9Sstevel@tonic-gate { 2, 0x3C3, MS2_map }, /* 21 */ 2607c478bd9Sstevel@tonic-gate #define FLAME0 (1ULL << 22) 2617c478bd9Sstevel@tonic-gate { 0, 0x3A6, FLAME0_map }, /* 22 */ 2627c478bd9Sstevel@tonic-gate #define FIRM0 (1ULL << 23) 2637c478bd9Sstevel@tonic-gate { 1, 0x3A4, FLAME0_map }, /* 23 */ 2647c478bd9Sstevel@tonic-gate #define SAAT0 (1ULL << 24) 2657c478bd9Sstevel@tonic-gate { 2, 0x3AE, FLAME0_map }, /* 24 */ 2667c478bd9Sstevel@tonic-gate #define U2L0 (1ULL << 25) 2677c478bd9Sstevel@tonic-gate { 3, 0x3B0, FLAME0_map }, /* 25 */ 2687c478bd9Sstevel@tonic-gate #define DAC0 (1ULL << 26) 2697c478bd9Sstevel@tonic-gate { 5, 0x3A8, FLAME0_map }, /* 26 */ 2707c478bd9Sstevel@tonic-gate #define FLAME1 (1ULL << 27) 2717c478bd9Sstevel@tonic-gate { 0, 0x3A7, FLAME2_map }, /* 27 */ 2727c478bd9Sstevel@tonic-gate #define FIRM1 (1ULL << 28) 2737c478bd9Sstevel@tonic-gate { 1, 0x3A5, FLAME2_map }, /* 28 */ 2747c478bd9Sstevel@tonic-gate #define SAAT1 (1ULL << 29) 2757c478bd9Sstevel@tonic-gate { 2, 0x3AF, FLAME2_map }, /* 29 */ 2767c478bd9Sstevel@tonic-gate #define U2L1 (1ULL << 30) 2777c478bd9Sstevel@tonic-gate { 3, 0x3B1, FLAME2_map }, /* 30 */ 2787c478bd9Sstevel@tonic-gate #define DAC1 (1ULL << 31) 2797c478bd9Sstevel@tonic-gate { 5, 0x3A9, FLAME2_map }, /* 31 */ 2807c478bd9Sstevel@tonic-gate #define IQ0 (1ULL << 32) 2817c478bd9Sstevel@tonic-gate { 0, 0x3BA, IQ0_map }, /* 32 */ 2827c478bd9Sstevel@tonic-gate #define ALF0 (1ULL << 33) 2837c478bd9Sstevel@tonic-gate { 1, 0x3CA, IQ0_map }, /* 33 */ 2847c478bd9Sstevel@tonic-gate #define RAT0 (1ULL << 34) 2857c478bd9Sstevel@tonic-gate { 2, 0x3BC, IQ0_map }, /* 34 */ 2867c478bd9Sstevel@tonic-gate #define SSU0 (1ULL << 35) 2877c478bd9Sstevel@tonic-gate { 3, 0x3BE, IQ0_map }, /* 35 */ 2887c478bd9Sstevel@tonic-gate #define CRU0 (1ULL << 36) 2897c478bd9Sstevel@tonic-gate { 4, 0x3B8, IQ0_map }, /* 36 */ 2907c478bd9Sstevel@tonic-gate #define CRU2 (1ULL << 37) 2917c478bd9Sstevel@tonic-gate { 5, 0x3CC, IQ0_map }, /* 37 */ 2927c478bd9Sstevel@tonic-gate #define CRU4 (1ULL << 38) 2937c478bd9Sstevel@tonic-gate { 6, 0x3E0, IQ0_map }, /* 38 */ 2947c478bd9Sstevel@tonic-gate #define IQ1 (1ULL << 39) 2957c478bd9Sstevel@tonic-gate { 0, 0x3BB, IQ2_map }, /* 39 */ 2967c478bd9Sstevel@tonic-gate #define ALF1 (1ULL << 40) 2977c478bd9Sstevel@tonic-gate { 1, 0x3CB, IQ2_map }, /* 40 */ 2987c478bd9Sstevel@tonic-gate #define RAT1 (1ULL << 41) 2997c478bd9Sstevel@tonic-gate { 2, 0x3BD, IQ2_map }, /* 41 */ 3007c478bd9Sstevel@tonic-gate #define CRU1 (1ULL << 42) 3017c478bd9Sstevel@tonic-gate { 4, 0x3B9, IQ2_map }, /* 42 */ 3027c478bd9Sstevel@tonic-gate #define CRU3 (1ULL << 43) 3037c478bd9Sstevel@tonic-gate { 5, 0x3CD, IQ2_map }, /* 43 */ 3047c478bd9Sstevel@tonic-gate #define CRU5 (1ULL << 44) 3057c478bd9Sstevel@tonic-gate { 6, 0x3E1, IQ2_map } /* 44 */ 3067c478bd9Sstevel@tonic-gate }; 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate #define ESCR_MAX_INDEX 44 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate typedef struct _p4_ctr { 3117c478bd9Sstevel@tonic-gate uint32_t pc_caddr; /* counter MSR address */ 3127c478bd9Sstevel@tonic-gate uint32_t pc_ctladdr; /* counter's CCCR MSR address */ 3137c478bd9Sstevel@tonic-gate uint64_t pc_map; /* bitmap of ESCRs controlling ctr */ 3147c478bd9Sstevel@tonic-gate } p4_ctr_t; 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate const p4_ctr_t p4_ctrs[18] = { 3177c478bd9Sstevel@tonic-gate { /* BPU_COUNTER0 */ 0x300, 0x360, BSU0|FSB0|MOB0|PMH0|BPU0|IS0|ITLB0|IX0}, 3187c478bd9Sstevel@tonic-gate { /* BPU_COUNTER1 */ 0x301, 0x361, BSU0|FSB0|MOB0|PMH0|BPU0|IS0|ITLB0|IX0}, 3197c478bd9Sstevel@tonic-gate { /* BPU_COUNTER2 */ 0x302, 0x362, BSU1|FSB1|MOB1|PMH1|BPU1|IS1|ITLB1|IX1}, 3207c478bd9Sstevel@tonic-gate { /* BPU_COUNTER3 */ 0x303, 0x363, BSU1|FSB1|MOB1|PMH1|BPU1|IS1|ITLB1|IX1}, 3217c478bd9Sstevel@tonic-gate { /* MS_COUNTER0 */ 0x304, 0x364, MS0|TBPU0|TC0 }, 3227c478bd9Sstevel@tonic-gate { /* MS_COUNTER1 */ 0x305, 0x365, MS0|TBPU0|TC0 }, 3237c478bd9Sstevel@tonic-gate { /* MS_COUNTER2 */ 0x306, 0x366, MS1|TBPU1|TC1 }, 3247c478bd9Sstevel@tonic-gate { /* MS_COUNTER3 */ 0x307, 0x367, MS1|TBPU1|TC1 }, 3257c478bd9Sstevel@tonic-gate { /* FLAME_COUNTER0 */ 0x308, 0x368, FIRM0|FLAME0|DAC0|SAAT0|U2L0 }, 3267c478bd9Sstevel@tonic-gate { /* FLAME_COUNTER1 */ 0x309, 0x369, FIRM0|FLAME0|DAC0|SAAT0|U2L0 }, 3277c478bd9Sstevel@tonic-gate { /* FLAME_COUNTER2 */ 0x30A, 0x36A, FIRM1|FLAME1|DAC1|SAAT1|U2L1 }, 3287c478bd9Sstevel@tonic-gate { /* FLAME_COUNTER3 */ 0x30B, 0x36B, FIRM1|FLAME1|DAC1|SAAT1|U2L1 }, 3297c478bd9Sstevel@tonic-gate { /* IQ_COUNTER0 */ 0x30C, 0x36C, CRU0|CRU2|CRU4|IQ0|RAT0|SSU0|ALF0 }, 3307c478bd9Sstevel@tonic-gate { /* IQ_COUNTER1 */ 0x30D, 0x36D, CRU0|CRU2|CRU4|IQ0|RAT0|SSU0|ALF0 }, 3317c478bd9Sstevel@tonic-gate { /* IQ_COUNTER2 */ 0x30E, 0x36E, CRU1|CRU3|CRU5|IQ1|RAT1|ALF1 }, 3327c478bd9Sstevel@tonic-gate { /* IQ_COUNTER3 */ 0x30F, 0x36F, CRU1|CRU3|CRU5|IQ1|RAT1|ALF1 }, 3337c478bd9Sstevel@tonic-gate { /* IQ_COUNTER4 */ 0x310, 0x370, CRU0|CRU2|CRU4|IQ0|RAT0|SSU0|ALF0 }, 3347c478bd9Sstevel@tonic-gate { /* IQ_COUNTER5 */ 0x311, 0x371, CRU1|CRU3|CRU5|IQ1|RAT1|ALF1 } 3357c478bd9Sstevel@tonic-gate }; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate typedef struct _p4_event { 3387c478bd9Sstevel@tonic-gate char *pe_name; /* Name of event according to docs */ 3397c478bd9Sstevel@tonic-gate uint64_t pe_escr_map; /* Bitmap of ESCRs capable of event */ 3407c478bd9Sstevel@tonic-gate uint32_t pe_escr_mask; /* permissible ESCR event mask */ 3417c478bd9Sstevel@tonic-gate uint8_t pe_ev; /* ESCR event select value */ 3427c478bd9Sstevel@tonic-gate uint16_t pe_cccr; /* CCCR select value */ 3437c478bd9Sstevel@tonic-gate uint32_t pe_ctr_mask; /* Bitmap of capable counters */ 3447c478bd9Sstevel@tonic-gate } p4_event_t; 3457c478bd9Sstevel@tonic-gate 346c7a079a8SJonathan Haslam typedef struct _p4_generic_event { 347c7a079a8SJonathan Haslam char *name; 348c7a079a8SJonathan Haslam char *event; 349c7a079a8SJonathan Haslam uint16_t emask; 350c7a079a8SJonathan Haslam uint32_t ctr_mask; 351c7a079a8SJonathan Haslam } p4_generic_event_t; 352c7a079a8SJonathan Haslam 3537c478bd9Sstevel@tonic-gate #define C(n) (1 << n) 354c7a079a8SJonathan Haslam #define GEN_EVT_END { NULL, NULL, 0x0, 0x0 } 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate p4_event_t p4_events[] = { 3577c478bd9Sstevel@tonic-gate { "branch_retired", CRU2|CRU3, 0xF, 0x6, 0x5, C(12)|C(13)|C(14)|C(15)|C(16) }, 3587c478bd9Sstevel@tonic-gate { "mispred_branch_retired", CRU0|CRU1, 0x1, 0x3, 0x4, 3597c478bd9Sstevel@tonic-gate C(12)|C(13)|C(14)|C(15)|C(16) }, 3607c478bd9Sstevel@tonic-gate { "TC_deliver_mode", TC0|TC1, 0xFF, 0x1, 0x1, C(4)|C(5)|C(6)|C(7) }, 3617c478bd9Sstevel@tonic-gate { "BPU_fetch_request", BPU0|BPU1, 0x1, 0x3, 0x0, C(0)|C(1)|C(2)|C(3) }, 3627c478bd9Sstevel@tonic-gate { "ITLB_reference", ITLB0|ITLB1, 0x7, 0x18, 0x3, C(0)|C(1)|C(2)|C(3) }, 3637c478bd9Sstevel@tonic-gate { "memory_cancel", DAC0|DAC1, 0x6, 0x2, 0x5, C(8)|C(9)|C(10)|C(11) }, 3647c478bd9Sstevel@tonic-gate { "memory_complete", SAAT0|SAAT1, 0x3, 0x8, 0x2, C(8)|C(9)|C(10)|C(11) }, 3657c478bd9Sstevel@tonic-gate { "load_port_replay", SAAT0|SAAT1, 0x1, 0x4, 0x2, C(8)|C(9)|C(10)|C(11) }, 3667c478bd9Sstevel@tonic-gate { "store_port_replay", SAAT0|SAAT1, 0x1, 0x5, 0x2, C(8)|C(9)|C(10)|C(11) }, 3677c478bd9Sstevel@tonic-gate { "MOB_load_replay", MOB0|MOB1, 0x35, 0x3, 0x2, C(0)|C(1)|C(2)|C(3) }, 3687c478bd9Sstevel@tonic-gate { "page_walk_type", PMH0|PMH1, 0x3, 0x1, 0x4, C(0)|C(1)|C(2)|C(3) }, 3697c478bd9Sstevel@tonic-gate { "BSQ_cache_reference", BSU0|BSU1, 0x73F, 0xC, 0x7, C(0)|C(1)|C(2)|C(3) }, 3707c478bd9Sstevel@tonic-gate { "IOQ_allocation", FSB0, 0xEFFF, 0x3, 0x6, C(0)|C(1) }, 3717c478bd9Sstevel@tonic-gate { "IOQ_active_entries", FSB1, 0xEFFF, 0x1A, 0x6, C(2)|C(3) }, 3727c478bd9Sstevel@tonic-gate { "FSB_data_activity", FSB0|FSB1, 0x3F, 0x17, 0x6, C(0)|C(1)|C(2)|C(3) }, 3737c478bd9Sstevel@tonic-gate { "BSQ_allocation", BSU0, 0x3FEF, 0x5, 0x7, C(0)|C(1) }, 3747c478bd9Sstevel@tonic-gate { "bsq_active_entries", BSU1, 0x3FEF, 0x6, 0x7, C(2)|C(3) }, 3757c478bd9Sstevel@tonic-gate { "x87_assist", CRU2|CRU3, 0x1F, 0x3, 0x5, C(12)|C(13)|C(14)|C(15)|C(16)|C(17)}, 3767c478bd9Sstevel@tonic-gate { "SSE_input_assist", FIRM0|FIRM1, 0x8000, 0x34, 0x1, C(8)|C(9)|C(10)|C(11) }, 3777c478bd9Sstevel@tonic-gate { "packed_SP_uop", FIRM0|FIRM1, 0x8000, 0x8, 0x1, C(8)|C(9)|C(10)|C(11) }, 3787c478bd9Sstevel@tonic-gate { "packed_DP_uop", FIRM0|FIRM1, 0x8000, 0xC, 0x1, C(8)|C(9)|C(10)|C(11) }, 3797c478bd9Sstevel@tonic-gate { "scalar_SP_uop", FIRM0|FIRM1, 0x8000, 0xA, 0x1, C(8)|C(9)|C(10)|C(11) }, 3807c478bd9Sstevel@tonic-gate { "scalar_DP_uop", FIRM0|FIRM1, 0x8000, 0xE, 0x1, C(8)|C(9)|C(10)|C(11) }, 3817c478bd9Sstevel@tonic-gate { "64bit_MMX_uop", FIRM0|FIRM1, 0x8000, 0x2, 0x1, C(8)|C(9)|C(10)|C(11) }, 3827c478bd9Sstevel@tonic-gate { "128bit_MMX_uop", FIRM0|FIRM1, 0x8000, 0x1A, 0x1, C(8)|C(9)|C(10)|C(11) }, 3837c478bd9Sstevel@tonic-gate { "x87_FP_uop", FIRM0|FIRM1, 0x8000, 0x4, 0x1, C(8)|C(9)|C(10)|C(11) }, 3847c478bd9Sstevel@tonic-gate { "x87_SIMD_moves_uop", FIRM0|FIRM1, 0x18, 0x2E, 0x1, C(8)|C(9)|C(10)|C(11) }, 3857c478bd9Sstevel@tonic-gate { "machine_clear", CRU2|CRU3, 0xD, 0x2, 0x5, 3867c478bd9Sstevel@tonic-gate C(12)|C(13)|C(14)|C(15)|C(16)|C(17)}, 387c7a079a8SJonathan Haslam { "global_power_events", FSB0|FSB1, 0x1, 0x13, 0x6, C(0)|C(1)|C(2)|C(3) }, 3887c478bd9Sstevel@tonic-gate { "tc_ms_xfer", MS0|MS1, 0x1, 0x5, 0x0, C(4)|C(5)|C(6)|C(7) }, 3897c478bd9Sstevel@tonic-gate { "uop_queue_writes", MS0|MS1, 0x7, 0x9, 0x0, C(4)|C(5)|C(6)|C(7) }, 3907c478bd9Sstevel@tonic-gate { "front_end_event", CRU2|CRU3, 0x3, 0x8, 0x5, 3917c478bd9Sstevel@tonic-gate C(12)|C(13)|C(14)|C(15)|C(16)|C(17)}, 3927c478bd9Sstevel@tonic-gate { "execution_event", CRU2|CRU3, 0xFF, 0xC, 0x5, 3937c478bd9Sstevel@tonic-gate C(12)|C(13)|C(14)|C(15)|C(16)|C(17)}, 3947c478bd9Sstevel@tonic-gate { "replay_event", CRU2|CRU3, 0x3, 0x9, 0x5, 3957c478bd9Sstevel@tonic-gate C(12)|C(13)|C(14)|C(15)|C(16)|C(17)}, 3967c478bd9Sstevel@tonic-gate { "instr_retired", CRU0|CRU1, 0xF, 0x2, 0x4, 3977c478bd9Sstevel@tonic-gate C(12)|C(13)|C(14)|C(15)|C(16)|C(17)}, 3987c478bd9Sstevel@tonic-gate { "uops_retired", CRU0|CRU1, 0x3, 0x1, 0x4, 3997c478bd9Sstevel@tonic-gate C(12)|C(13)|C(14)|C(15)|C(16)|C(17)}, 4007c478bd9Sstevel@tonic-gate { "uop_type", RAT0|RAT1, 0x3, 0x2, 0x2, C(12)|C(13)|C(14)|C(15)|C(16)|C(17)}, 4017c478bd9Sstevel@tonic-gate { "retired_mispred_branch_type", TBPU0|TBPU1, 0x1F, 0x5, 0x2, 4027c478bd9Sstevel@tonic-gate C(4)|C(5)|C(6)|C(7)}, 4037c478bd9Sstevel@tonic-gate { "retired_branch_type", TBPU0|TBPU1, 0x1F, 0x4, 0x2, C(4)|C(5)|C(6)|C(7) }, 4047c478bd9Sstevel@tonic-gate { NULL, 0, 0, 0, 0 } 4057c478bd9Sstevel@tonic-gate }; 4067c478bd9Sstevel@tonic-gate 407c7a079a8SJonathan Haslam static p4_generic_event_t p4_generic_events[] = { 408c7a079a8SJonathan Haslam { "PAPI_br_msp", "branch_retired", 0xa, C(12)|C(13)|C(14)|C(15)|C(16) }, 409c7a079a8SJonathan Haslam { "PAPI_br_ins", "branch_retired", 0xf, C(12)|C(13)|C(14)|C(15)|C(16) }, 410c7a079a8SJonathan Haslam { "PAPI_br_tkn", "branch_retired", 0xc, C(12)|C(13)|C(14)|C(15)|C(16) }, 411c7a079a8SJonathan Haslam { "PAPI_br_ntk", "branch_retired", 0x3, C(12)|C(13)|C(14)|C(15)|C(16) }, 412c7a079a8SJonathan Haslam { "PAPI_br_prc", "branch_retired", 0x5, C(12)|C(13)|C(14)|C(15)|C(16) }, 413c7a079a8SJonathan Haslam { "PAPI_tot_ins", "instr_retired", 0x3, C(12)|C(13)|C(14)|C(15)|C(16)|C(17) }, 414c7a079a8SJonathan Haslam { "PAPI_tot_cyc", "global_power_events", 0x1, C(0)|C(1)|C(2)|C(3) }, 415c7a079a8SJonathan Haslam { "PAPI_tlb_dm", "page_walk_type", 0x1, C(0)|C(1)|C(2)|C(3) }, 416c7a079a8SJonathan Haslam { "PAPI_tlb_im", "page_walk_type", 0x2, C(0)|C(1)|C(2)|C(3) }, 417c7a079a8SJonathan Haslam { "PAPI_tlb_tm", "page_walk_type", 0x3, C(0)|C(1)|C(2)|C(3) }, 418c7a079a8SJonathan Haslam { "PAPI_l1_icm", "BPU_fetch_request", 0x1, C(0)|C(1)|C(2)|C(3) }, 419c7a079a8SJonathan Haslam { "PAPI_l2_ldm", "BSQ_cache_reference", 0x100, C(0)|C(1)|C(2)|C(3) }, 420c7a079a8SJonathan Haslam { "PAPI_l2_stm", "BSQ_cache_reference", 0x400, C(0)|C(1)|C(2)|C(3) }, 421c7a079a8SJonathan Haslam { "PAPI_l2_tcm", "BSQ_cache_reference", 0x500, C(0)|C(1)|C(2)|C(3) }, 422c7a079a8SJonathan Haslam GEN_EVT_END 423c7a079a8SJonathan Haslam }; 424c7a079a8SJonathan Haslam 4257c478bd9Sstevel@tonic-gate /* 4267c478bd9Sstevel@tonic-gate * Indicates whether the "rdpmc" instruction is available on this processor. 4277c478bd9Sstevel@tonic-gate */ 4287c478bd9Sstevel@tonic-gate static int p4_rdpmc_avail = 0; 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate static const uint64_t p4_cccrstop = 0; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate static char *p4_eventlist[18]; 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate /* 4357c478bd9Sstevel@tonic-gate * If set, this processor has HyperThreading. 4367c478bd9Sstevel@tonic-gate */ 4377c478bd9Sstevel@tonic-gate static int p4_htt = 0; 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate #define P4_FAMILY 0xF 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate static int 4427c478bd9Sstevel@tonic-gate p4_pcbe_init(void) 4437c478bd9Sstevel@tonic-gate { 4447c478bd9Sstevel@tonic-gate int i; 4457c478bd9Sstevel@tonic-gate size_t size; 4467c478bd9Sstevel@tonic-gate p4_event_t *ev; 447c7a079a8SJonathan Haslam p4_generic_event_t *gevp; 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate /* 4507c478bd9Sstevel@tonic-gate * If we're not running on a P4, refuse to load. 4517c478bd9Sstevel@tonic-gate */ 4527c478bd9Sstevel@tonic-gate if (cpuid_getvendor(CPU) != X86_VENDOR_Intel || 4537c478bd9Sstevel@tonic-gate cpuid_getfamily(CPU) != P4_FAMILY) 4547c478bd9Sstevel@tonic-gate return (-1); 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate /* 4577c478bd9Sstevel@tonic-gate * Set up the event lists for each counter. 4587c478bd9Sstevel@tonic-gate * 4597c478bd9Sstevel@tonic-gate * First pass calculates the size of the event list, and the second 4607c478bd9Sstevel@tonic-gate * pass copies each event name into the event list. 4617c478bd9Sstevel@tonic-gate */ 4627c478bd9Sstevel@tonic-gate for (i = 0; i < 18; i++) { 4637c478bd9Sstevel@tonic-gate size = 0; 464c7a079a8SJonathan Haslam 4657c478bd9Sstevel@tonic-gate for (ev = p4_events; ev->pe_name != NULL; ev++) { 4667c478bd9Sstevel@tonic-gate if (ev->pe_ctr_mask & C(i)) 4677c478bd9Sstevel@tonic-gate size += strlen(ev->pe_name) + 1; 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate 470c7a079a8SJonathan Haslam for (gevp = p4_generic_events; gevp->name != NULL; gevp++) { 471c7a079a8SJonathan Haslam if (gevp->ctr_mask & C(i)) 472c7a079a8SJonathan Haslam size += strlen(gevp->name) + 1; 473c7a079a8SJonathan Haslam } 474c7a079a8SJonathan Haslam 4757c478bd9Sstevel@tonic-gate /* 4767c478bd9Sstevel@tonic-gate * We use 'size + 1' here to ensure room for the final 4777c478bd9Sstevel@tonic-gate * strcat when it terminates the string. 4787c478bd9Sstevel@tonic-gate */ 4797c478bd9Sstevel@tonic-gate p4_eventlist[i] = (char *)kmem_alloc(size + 1, KM_SLEEP); 4807c478bd9Sstevel@tonic-gate *p4_eventlist[i] = '\0'; 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate for (ev = p4_events; ev->pe_name != NULL; ev++) { 4837c478bd9Sstevel@tonic-gate if (ev->pe_ctr_mask & C(i)) { 4847c478bd9Sstevel@tonic-gate (void) strcat(p4_eventlist[i], ev->pe_name); 4857c478bd9Sstevel@tonic-gate (void) strcat(p4_eventlist[i], ","); 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate } 488c7a079a8SJonathan Haslam 489c7a079a8SJonathan Haslam for (gevp = p4_generic_events; gevp->name != NULL; gevp++) { 490c7a079a8SJonathan Haslam if (gevp->ctr_mask & C(i)) { 491c7a079a8SJonathan Haslam (void) strcat(p4_eventlist[i], gevp->name); 492c7a079a8SJonathan Haslam (void) strcat(p4_eventlist[i], ","); 493c7a079a8SJonathan Haslam } 494c7a079a8SJonathan Haslam } 495c7a079a8SJonathan Haslam 4967c478bd9Sstevel@tonic-gate /* 4977c478bd9Sstevel@tonic-gate * Remove trailing ',' 4987c478bd9Sstevel@tonic-gate */ 4997c478bd9Sstevel@tonic-gate p4_eventlist[i][size - 1] = '\0'; 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 502*7417cfdeSKuriakose Kuruvilla if (is_x86_feature(x86_featureset, X86FSET_MMX)) 5037c478bd9Sstevel@tonic-gate p4_rdpmc_avail = 1; 5047c478bd9Sstevel@tonic-gate /* 5057c478bd9Sstevel@tonic-gate * The X86_HTT flag may disappear soon, so we'll isolate the impact of 5067c478bd9Sstevel@tonic-gate * its demise to the following if(). 5077c478bd9Sstevel@tonic-gate */ 508*7417cfdeSKuriakose Kuruvilla if (is_x86_feature(x86_featureset, X86FSET_HTT)) 5097c478bd9Sstevel@tonic-gate p4_htt = 1; 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate return (0); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate static uint_t 5157c478bd9Sstevel@tonic-gate p4_pcbe_ncounters(void) 5167c478bd9Sstevel@tonic-gate { 5177c478bd9Sstevel@tonic-gate return (18); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate static const char * 5217c478bd9Sstevel@tonic-gate p4_pcbe_impl_name(void) 5227c478bd9Sstevel@tonic-gate { 5237c478bd9Sstevel@tonic-gate if (p4_htt) 524b885580bSAlexander Kolbasov return (PCBE_IMPL_NAME_P4HT); 5257c478bd9Sstevel@tonic-gate return ("Pentium 4"); 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate static const char * 5297c478bd9Sstevel@tonic-gate p4_pcbe_cpuref(void) 5307c478bd9Sstevel@tonic-gate { 5317c478bd9Sstevel@tonic-gate return ("See Appendix A.1 of the \"IA-32 Intel Architecture Software " \ 5327c478bd9Sstevel@tonic-gate "Developer's Manual Volume 3: System Programming Guide,\" " \ 5337c478bd9Sstevel@tonic-gate "Order # 245472-012, 2003"); 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate static char * 5377c478bd9Sstevel@tonic-gate p4_pcbe_list_events(uint_t picnum) 5387c478bd9Sstevel@tonic-gate { 5397c478bd9Sstevel@tonic-gate ASSERT(picnum >= 0 && picnum < 18); 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate return (p4_eventlist[picnum]); 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate #define P4_ATTRS "emask,tag,compare,complement,threshold,edge" 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate static char * 5477c478bd9Sstevel@tonic-gate p4_pcbe_list_attrs(void) 5487c478bd9Sstevel@tonic-gate { 5497c478bd9Sstevel@tonic-gate if (p4_htt) 5507c478bd9Sstevel@tonic-gate return (P4_ATTRS ",active_thread,count_sibling_usr," 5517c478bd9Sstevel@tonic-gate "count_sibling_sys"); 5527c478bd9Sstevel@tonic-gate return (P4_ATTRS); 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate 555c7a079a8SJonathan Haslam static p4_generic_event_t * 556c7a079a8SJonathan Haslam find_generic_event(char *name) 557c7a079a8SJonathan Haslam { 558c7a079a8SJonathan Haslam p4_generic_event_t *gevp; 559c7a079a8SJonathan Haslam 56049f52d51SKuriakose Kuruvilla for (gevp = p4_generic_events; gevp->name != NULL; gevp++) 561c7a079a8SJonathan Haslam if (strcmp(name, gevp->name) == 0) 562c7a079a8SJonathan Haslam return (gevp); 563c7a079a8SJonathan Haslam 564c7a079a8SJonathan Haslam return (NULL); 565c7a079a8SJonathan Haslam } 566c7a079a8SJonathan Haslam 567c7a079a8SJonathan Haslam static p4_event_t * 568c7a079a8SJonathan Haslam find_event(char *name) 569c7a079a8SJonathan Haslam { 570c7a079a8SJonathan Haslam p4_event_t *evp; 571c7a079a8SJonathan Haslam 572c7a079a8SJonathan Haslam for (evp = p4_events; evp->pe_name != NULL; evp++) 573c7a079a8SJonathan Haslam if (strcmp(name, evp->pe_name) == 0) 574c7a079a8SJonathan Haslam return (evp); 575c7a079a8SJonathan Haslam 576c7a079a8SJonathan Haslam return (NULL); 577c7a079a8SJonathan Haslam } 578c7a079a8SJonathan Haslam 5797c478bd9Sstevel@tonic-gate static uint64_t 5807c478bd9Sstevel@tonic-gate p4_pcbe_event_coverage(char *event) 5817c478bd9Sstevel@tonic-gate { 5827c478bd9Sstevel@tonic-gate p4_event_t *ev; 583c7a079a8SJonathan Haslam p4_generic_event_t *gevp; 5847c478bd9Sstevel@tonic-gate 585c7a079a8SJonathan Haslam if ((ev = find_event(event)) == NULL) { 586c7a079a8SJonathan Haslam if ((gevp = find_generic_event(event)) != NULL) 587c7a079a8SJonathan Haslam return (gevp->ctr_mask); 588c7a079a8SJonathan Haslam else 589c7a079a8SJonathan Haslam return (0); 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate return (ev->pe_ctr_mask); 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate static uint64_t 5967c478bd9Sstevel@tonic-gate p4_pcbe_overflow_bitmap(void) 5977c478bd9Sstevel@tonic-gate { 5987c478bd9Sstevel@tonic-gate extern int kcpc_hw_overflow_intr_installed; 5997c478bd9Sstevel@tonic-gate uint64_t ret = 0; 6007c478bd9Sstevel@tonic-gate int i; 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate /* 6037c478bd9Sstevel@tonic-gate * The CCCR's OVF bit indicates that the corresponding counter has 6047c478bd9Sstevel@tonic-gate * overflowed. It must be explicitly cleared by software, so it is 6057c478bd9Sstevel@tonic-gate * safe to read the CCCR values here. 6067c478bd9Sstevel@tonic-gate */ 6077c478bd9Sstevel@tonic-gate for (i = 0; i < 18; i++) { 6080ac7d7d8Skucharsk if (rdmsr(p4_ctrs[i].pc_ctladdr) & CCCR_OVF) 6097c478bd9Sstevel@tonic-gate ret |= (1 << i); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate /* 6137c478bd9Sstevel@tonic-gate * Pentium 4 and Xeon turn off the CPC interrupt mask bit in the LVT at 6147c478bd9Sstevel@tonic-gate * every overflow. Turn it back on here. 6157c478bd9Sstevel@tonic-gate */ 6167c478bd9Sstevel@tonic-gate ASSERT(kcpc_hw_overflow_intr_installed); 6177c478bd9Sstevel@tonic-gate (*kcpc_hw_enable_cpc_intr)(); 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate return (ret); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate static int 6237c478bd9Sstevel@tonic-gate p4_escr_inuse(p4_pcbe_config_t **cfgs, int escr_ndx) 6247c478bd9Sstevel@tonic-gate { 6257c478bd9Sstevel@tonic-gate int i; 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate for (i = 0; i < 18; i++) { 6287c478bd9Sstevel@tonic-gate if (cfgs[i] == NULL) 6297c478bd9Sstevel@tonic-gate continue; 6307c478bd9Sstevel@tonic-gate if (cfgs[i]->p4_escr_ndx == escr_ndx) 6317c478bd9Sstevel@tonic-gate return (1); 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate return (0); 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate static void 6387c478bd9Sstevel@tonic-gate build_cfgs(p4_pcbe_config_t *cfgs[18], uint64_t *data[18], void *token) 6397c478bd9Sstevel@tonic-gate { 6407c478bd9Sstevel@tonic-gate p4_pcbe_config_t *cfg = NULL; 6417c478bd9Sstevel@tonic-gate uint64_t *daddr; 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate bzero(cfgs, 18 * sizeof (p4_pcbe_config_t *)); 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate do { 6467c478bd9Sstevel@tonic-gate cfg = (p4_pcbe_config_t *)kcpc_next_config(token, cfg, &daddr); 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate if (cfg != NULL) { 6497c478bd9Sstevel@tonic-gate ASSERT(cfg->p4_picno < 18); 6507c478bd9Sstevel@tonic-gate cfgs[cfg->p4_picno] = cfg; 6517c478bd9Sstevel@tonic-gate if (data != NULL) { 6527c478bd9Sstevel@tonic-gate ASSERT(daddr != NULL); 6537c478bd9Sstevel@tonic-gate data[cfg->p4_picno] = daddr; 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate } while (cfg != NULL); 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate /* 6607c478bd9Sstevel@tonic-gate * Programming a counter: 6617c478bd9Sstevel@tonic-gate * 6627c478bd9Sstevel@tonic-gate * Select event. 6637c478bd9Sstevel@tonic-gate * Choose an ESCR capable of counting that event. 6647c478bd9Sstevel@tonic-gate * Set up the ESCR with the desired parameters (usr, sys, tag). 6657c478bd9Sstevel@tonic-gate * Set up the CCCR to point to the selected ESCR. 6667c478bd9Sstevel@tonic-gate * Set the CCCR parameters (overflow, cascade, edge, etc). 6677c478bd9Sstevel@tonic-gate */ 6687c478bd9Sstevel@tonic-gate static int 6697c478bd9Sstevel@tonic-gate p4_pcbe_configure(uint_t picnum, char *eventname, uint64_t preset, 6707c478bd9Sstevel@tonic-gate uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data, 6717c478bd9Sstevel@tonic-gate void *token) 6727c478bd9Sstevel@tonic-gate { 6737c478bd9Sstevel@tonic-gate p4_pcbe_config_t *cfgs[18]; 6747c478bd9Sstevel@tonic-gate p4_pcbe_config_t *cfg; 6757c478bd9Sstevel@tonic-gate p4_event_t *ev; 676c7a079a8SJonathan Haslam p4_generic_event_t *gevp; 6777c478bd9Sstevel@tonic-gate int escr_ndx; 6787c478bd9Sstevel@tonic-gate int i; 6797c478bd9Sstevel@tonic-gate uint16_t emask = 0; 6807c478bd9Sstevel@tonic-gate uint8_t tag; 6817c478bd9Sstevel@tonic-gate int use_tag = 0; 6827c478bd9Sstevel@tonic-gate int active_thread = 0x3; /* default is "any" */ 6837c478bd9Sstevel@tonic-gate int compare = 0; 6847c478bd9Sstevel@tonic-gate int complement = 0; 6857c478bd9Sstevel@tonic-gate int threshold = 0; 6867c478bd9Sstevel@tonic-gate int edge = 0; 6877c478bd9Sstevel@tonic-gate int sibling_usr = 0; /* count usr on other cpu */ 6887c478bd9Sstevel@tonic-gate int sibling_sys = 0; /* count sys on other cpu */ 689c7a079a8SJonathan Haslam int invalid_attr = 0; 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /* 6927c478bd9Sstevel@tonic-gate * If we've been handed an existing configuration, we need only preset 6937c478bd9Sstevel@tonic-gate * the counter value. 6947c478bd9Sstevel@tonic-gate */ 6957c478bd9Sstevel@tonic-gate if (*data != NULL) { 6967c478bd9Sstevel@tonic-gate cfg = *data; 6977c478bd9Sstevel@tonic-gate cfg->p4_rawpic = preset & MASK40; 6987c478bd9Sstevel@tonic-gate return (0); 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate if (picnum < 0 || picnum >= 18) 7027c478bd9Sstevel@tonic-gate return (CPC_INVALID_PICNUM); 7037c478bd9Sstevel@tonic-gate 704c7a079a8SJonathan Haslam if ((ev = find_event(eventname)) == NULL) { 705c7a079a8SJonathan Haslam if ((gevp = find_generic_event(eventname)) != NULL) { 706c7a079a8SJonathan Haslam ev = find_event(gevp->event); 707c7a079a8SJonathan Haslam ASSERT(ev != NULL); 708c7a079a8SJonathan Haslam 709c7a079a8SJonathan Haslam /* 710c7a079a8SJonathan Haslam * For generic events a HTT processor is only allowed 711c7a079a8SJonathan Haslam * to specify the 'active_thread', 'count_sibling_usr' 712c7a079a8SJonathan Haslam * and 'count_sibling_sys' attributes. 713c7a079a8SJonathan Haslam */ 714c7a079a8SJonathan Haslam if (p4_htt) 715c7a079a8SJonathan Haslam for (i = 0; i < nattrs; i++) 716c7a079a8SJonathan Haslam if (strstr(P4_ATTRS, 717c7a079a8SJonathan Haslam attrs[i].ka_name) != NULL) 718c7a079a8SJonathan Haslam invalid_attr = 1; 719c7a079a8SJonathan Haslam 720c7a079a8SJonathan Haslam if ((p4_htt && invalid_attr) || 721c7a079a8SJonathan Haslam (!p4_htt && nattrs > 0)) 722c7a079a8SJonathan Haslam return (CPC_ATTRIBUTE_OUT_OF_RANGE); 723c7a079a8SJonathan Haslam 724c7a079a8SJonathan Haslam emask = gevp->emask; 725c7a079a8SJonathan Haslam } else { 7267c478bd9Sstevel@tonic-gate return (CPC_INVALID_EVENT); 727c7a079a8SJonathan Haslam } 728c7a079a8SJonathan Haslam } 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate build_cfgs(cfgs, NULL, token); 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate /* 7337c478bd9Sstevel@tonic-gate * Find an ESCR capable of counting this event. 7347c478bd9Sstevel@tonic-gate */ 7357c478bd9Sstevel@tonic-gate for (escr_ndx = 0; escr_ndx < ESCR_MAX_INDEX; escr_ndx++) { 7367c478bd9Sstevel@tonic-gate if ((ev->pe_escr_map & (1ULL << escr_ndx)) && 7377c478bd9Sstevel@tonic-gate p4_escr_inuse(cfgs, escr_ndx) == 0) 7387c478bd9Sstevel@tonic-gate break; 7397c478bd9Sstevel@tonic-gate } 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate /* 7427c478bd9Sstevel@tonic-gate * All ESCRs capable of counting this event are already being 7437c478bd9Sstevel@tonic-gate * used. 7447c478bd9Sstevel@tonic-gate */ 7457c478bd9Sstevel@tonic-gate if (escr_ndx == ESCR_MAX_INDEX) 7467c478bd9Sstevel@tonic-gate return (CPC_RESOURCE_UNAVAIL); 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate /* 7497c478bd9Sstevel@tonic-gate * At this point, ev points to the desired event and escr is the index 7507c478bd9Sstevel@tonic-gate * of a capable and available ESCR. 7517c478bd9Sstevel@tonic-gate * 7527c478bd9Sstevel@tonic-gate * Now process and verify the attributes. 7537c478bd9Sstevel@tonic-gate */ 7547c478bd9Sstevel@tonic-gate for (i = 0; i < nattrs; i++) { 7557c478bd9Sstevel@tonic-gate if (strcmp("emask", attrs[i].ka_name) == 0) { 7567c478bd9Sstevel@tonic-gate if ((attrs[i].ka_val | ev->pe_escr_mask) 7577c478bd9Sstevel@tonic-gate != ev->pe_escr_mask) 7587c478bd9Sstevel@tonic-gate return (CPC_ATTRIBUTE_OUT_OF_RANGE); 7597c478bd9Sstevel@tonic-gate emask = attrs[i].ka_val; 7607c478bd9Sstevel@tonic-gate continue; 7617c478bd9Sstevel@tonic-gate } else if (strcmp("tag", attrs[i].ka_name) == 0) { 7627c478bd9Sstevel@tonic-gate if (attrs[i].ka_val > ESCR_TAG_VALUE_MAX) 7637c478bd9Sstevel@tonic-gate return (CPC_ATTRIBUTE_OUT_OF_RANGE); 7647c478bd9Sstevel@tonic-gate tag = attrs[i].ka_val; 7657c478bd9Sstevel@tonic-gate use_tag = 1; 7667c478bd9Sstevel@tonic-gate continue; 7677c478bd9Sstevel@tonic-gate } else if (strcmp("compare", attrs[i].ka_name) == 0) { 7687c478bd9Sstevel@tonic-gate if (attrs[i].ka_val != 0) 7697c478bd9Sstevel@tonic-gate compare = 1; 7707c478bd9Sstevel@tonic-gate continue; 7717c478bd9Sstevel@tonic-gate } else if (strcmp("complement", attrs[i].ka_name) == 0) { 7727c478bd9Sstevel@tonic-gate if (attrs[i].ka_val != 0) 7737c478bd9Sstevel@tonic-gate complement = 1; 7747c478bd9Sstevel@tonic-gate continue; 7757c478bd9Sstevel@tonic-gate } else if (strcmp("threshold", attrs[i].ka_name) == 0) { 7767c478bd9Sstevel@tonic-gate if (attrs[i].ka_val > CCCR_THRESHOLD_MAX) 7777c478bd9Sstevel@tonic-gate return (CPC_ATTRIBUTE_OUT_OF_RANGE); 7787c478bd9Sstevel@tonic-gate threshold = attrs[i].ka_val; 7797c478bd9Sstevel@tonic-gate continue; 7807c478bd9Sstevel@tonic-gate } else if (strcmp("edge", attrs[i].ka_name) == 0) { 7817c478bd9Sstevel@tonic-gate if (attrs[i].ka_val != 0) 7827c478bd9Sstevel@tonic-gate edge = 1; 7837c478bd9Sstevel@tonic-gate continue; 7847c478bd9Sstevel@tonic-gate } 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate /* 7877c478bd9Sstevel@tonic-gate * The remaining attributes are valid only on HyperThreaded P4s 7887c478bd9Sstevel@tonic-gate * for processes with the "cpc_cpu" privilege. 7897c478bd9Sstevel@tonic-gate */ 7907c478bd9Sstevel@tonic-gate if (p4_htt == 0) 7917c478bd9Sstevel@tonic-gate return (CPC_INVALID_ATTRIBUTE); 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate if (secpolicy_cpc_cpu(crgetcred()) != 0) 7947c478bd9Sstevel@tonic-gate return (CPC_ATTR_REQUIRES_PRIVILEGE); 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate if (strcmp("active_thread", attrs[i].ka_name) == 0) { 7977c478bd9Sstevel@tonic-gate if ((attrs[i].ka_val | CCCR_ACTV_THR_MASK) != 7987c478bd9Sstevel@tonic-gate CCCR_ACTV_THR_MASK) 7997c478bd9Sstevel@tonic-gate return (CPC_ATTRIBUTE_OUT_OF_RANGE); 8007c478bd9Sstevel@tonic-gate active_thread = (int)attrs[i].ka_val; 8017c478bd9Sstevel@tonic-gate } else if (strcmp("count_sibling_usr", attrs[i].ka_name) == 0) { 8027c478bd9Sstevel@tonic-gate if (attrs[i].ka_val != 0) 8037c478bd9Sstevel@tonic-gate sibling_usr = 1; 8047c478bd9Sstevel@tonic-gate } else if (strcmp("count_sibling_sys", attrs[i].ka_name) == 0) { 8057c478bd9Sstevel@tonic-gate if (attrs[i].ka_val != 0) 8067c478bd9Sstevel@tonic-gate sibling_sys = 1; 8077c478bd9Sstevel@tonic-gate } else 8087c478bd9Sstevel@tonic-gate return (CPC_INVALID_ATTRIBUTE); 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate /* 8127c478bd9Sstevel@tonic-gate * Make sure the counter can count this event 8137c478bd9Sstevel@tonic-gate */ 8147c478bd9Sstevel@tonic-gate if ((ev->pe_ctr_mask & C(picnum)) == 0) 8157c478bd9Sstevel@tonic-gate return (CPC_PIC_NOT_CAPABLE); 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate /* 8187c478bd9Sstevel@tonic-gate * Find an ESCR that lines up with the event _and_ the counter. 8197c478bd9Sstevel@tonic-gate */ 8207c478bd9Sstevel@tonic-gate for (escr_ndx = 0; escr_ndx < ESCR_MAX_INDEX; escr_ndx++) { 8217c478bd9Sstevel@tonic-gate if ((ev->pe_escr_map & (1ULL << escr_ndx)) && 8227c478bd9Sstevel@tonic-gate (p4_escrs[escr_ndx].pe_map & (1 << picnum)) && 8237c478bd9Sstevel@tonic-gate p4_escr_inuse(cfgs, escr_ndx) == 0) 8247c478bd9Sstevel@tonic-gate break; 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate if (escr_ndx == ESCR_MAX_INDEX) 8277c478bd9Sstevel@tonic-gate return (CPC_RESOURCE_UNAVAIL); 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate cfg = (p4_pcbe_config_t *)kmem_alloc(sizeof (p4_pcbe_config_t), 8307c478bd9Sstevel@tonic-gate KM_SLEEP); 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate cfg->p4_flags = 0; 8337c478bd9Sstevel@tonic-gate cfg->p4_picno = picnum; 8347c478bd9Sstevel@tonic-gate cfg->p4_escr_ndx = escr_ndx; 8357c478bd9Sstevel@tonic-gate cfg->p4_escr = (ev->pe_ev << ESCR_EVSEL_SHIFT) | 8367c478bd9Sstevel@tonic-gate (emask << ESCR_EVMASK_SHIFT); 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate if (use_tag == 1) { 8397c478bd9Sstevel@tonic-gate cfg->p4_escr |= tag << ESCR_TAG_VALUE_SHIFT; 8407c478bd9Sstevel@tonic-gate cfg->p4_escr |= ESCR_TAG_ENABLE; 8417c478bd9Sstevel@tonic-gate } 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate if (p4_htt) { 8447c478bd9Sstevel@tonic-gate /* 8457c478bd9Sstevel@tonic-gate * This is a HyperThreaded P4. Since we don't know which 8467c478bd9Sstevel@tonic-gate * logical CPU this configuration will eventually be programmed 8477c478bd9Sstevel@tonic-gate * on, we can't yet decide which fields of the ESCR to select. 8487c478bd9Sstevel@tonic-gate * 8497c478bd9Sstevel@tonic-gate * Record the necessary information in the flags for later. 8507c478bd9Sstevel@tonic-gate */ 8517c478bd9Sstevel@tonic-gate if (flags & CPC_COUNT_USER) 8527c478bd9Sstevel@tonic-gate cfg->p4_flags |= P4_THIS_USR; 8537c478bd9Sstevel@tonic-gate if (flags & CPC_COUNT_SYSTEM) 8547c478bd9Sstevel@tonic-gate cfg->p4_flags |= P4_THIS_SYS; 8557c478bd9Sstevel@tonic-gate if (p4_htt && sibling_usr) 8567c478bd9Sstevel@tonic-gate cfg->p4_flags |= P4_SIBLING_USR; 8577c478bd9Sstevel@tonic-gate if (p4_htt && sibling_sys) 8587c478bd9Sstevel@tonic-gate cfg->p4_flags |= P4_SIBLING_SYS; 8597c478bd9Sstevel@tonic-gate } else { 8607c478bd9Sstevel@tonic-gate /* 8617c478bd9Sstevel@tonic-gate * This is not HyperThreaded, so we can determine the exact 8627c478bd9Sstevel@tonic-gate * ESCR value necessary now. 8637c478bd9Sstevel@tonic-gate */ 8647c478bd9Sstevel@tonic-gate if (flags & CPC_COUNT_USER) 8657c478bd9Sstevel@tonic-gate cfg->p4_escr |= ESCR_USR; 8667c478bd9Sstevel@tonic-gate if (flags & CPC_COUNT_SYSTEM) 8677c478bd9Sstevel@tonic-gate cfg->p4_escr |= ESCR_OS; 8687c478bd9Sstevel@tonic-gate } 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate cfg->p4_rawpic = preset & MASK40; 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate /* 8737c478bd9Sstevel@tonic-gate * Even on non-HT P4s, Intel states the active_thread field (marked as 8747c478bd9Sstevel@tonic-gate * "reserved" for the non-HT chips) must be set to all 1s. 8757c478bd9Sstevel@tonic-gate */ 8767c478bd9Sstevel@tonic-gate cfg->p4_cccr = CCCR_INIT | (active_thread << CCCR_ACTV_THR_SHIFT); 8777c478bd9Sstevel@tonic-gate if (compare) 8787c478bd9Sstevel@tonic-gate cfg->p4_cccr |= CCCR_COMPARE; 8797c478bd9Sstevel@tonic-gate if (complement) 8807c478bd9Sstevel@tonic-gate cfg->p4_cccr |= CCCR_COMPLEMENT; 8817c478bd9Sstevel@tonic-gate cfg->p4_cccr |= threshold << CCCR_THRESHOLD_SHIFT; 8827c478bd9Sstevel@tonic-gate if (edge) 8837c478bd9Sstevel@tonic-gate cfg->p4_cccr |= CCCR_EDGE; 8847c478bd9Sstevel@tonic-gate cfg->p4_cccr |= p4_escrs[cfg->p4_escr_ndx].pe_num 8857c478bd9Sstevel@tonic-gate << CCCR_ESCR_SEL_SHIFT; 8867c478bd9Sstevel@tonic-gate if (flags & CPC_OVF_NOTIFY_EMT) { 8877c478bd9Sstevel@tonic-gate if (p4_htt) 8887c478bd9Sstevel@tonic-gate cfg->p4_flags |= P4_PMI; 8897c478bd9Sstevel@tonic-gate else { 8907c478bd9Sstevel@tonic-gate /* 8917c478bd9Sstevel@tonic-gate * If the user has asked for notification of overflows, 8927c478bd9Sstevel@tonic-gate * we automatically program the hardware to generate an 8937c478bd9Sstevel@tonic-gate * interrupt on overflow. 8947c478bd9Sstevel@tonic-gate * 8957c478bd9Sstevel@tonic-gate * This can only be programmed now if this P4 doesn't 8967c478bd9Sstevel@tonic-gate * have HyperThreading. If it does, we must wait until 8977c478bd9Sstevel@tonic-gate * we know which logical CPU we'll be programming. 8987c478bd9Sstevel@tonic-gate */ 8997c478bd9Sstevel@tonic-gate cfg->p4_cccr |= CCCR_OVF_PMI; 9007c478bd9Sstevel@tonic-gate } 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate *data = cfg; 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate return (0); 9067c478bd9Sstevel@tonic-gate } 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate static void 9097c478bd9Sstevel@tonic-gate p4_pcbe_program(void *token) 9107c478bd9Sstevel@tonic-gate { 9117c478bd9Sstevel@tonic-gate int i; 9127c478bd9Sstevel@tonic-gate uint64_t cccr; 9137c478bd9Sstevel@tonic-gate p4_pcbe_config_t *cfgs[18]; 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate p4_pcbe_allstop(); 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate build_cfgs(cfgs, NULL, token); 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate if (p4_rdpmc_avail) { 920843e1988Sjohnlev ulong_t curcr4 = getcr4(); 9217c478bd9Sstevel@tonic-gate if (kcpc_allow_nonpriv(token)) 9227c478bd9Sstevel@tonic-gate setcr4(curcr4 | CR4_PCE); 9237c478bd9Sstevel@tonic-gate else 9247c478bd9Sstevel@tonic-gate setcr4(curcr4 & ~CR4_PCE); 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate /* 9287c478bd9Sstevel@tonic-gate * Ideally we would start all counters with a single operation, but in 9297c478bd9Sstevel@tonic-gate * P4 each counter is enabled individually via its CCCR. To minimize the 9307c478bd9Sstevel@tonic-gate * probe effect of enabling the counters, we do it in two passes: the 9317c478bd9Sstevel@tonic-gate * first programs the counter and ESCR, and the second programs the 9327c478bd9Sstevel@tonic-gate * CCCR (and thus enables the counter). 9337c478bd9Sstevel@tonic-gate */ 9347c478bd9Sstevel@tonic-gate if (p4_htt) { 935fb2f18f8Sesaxe int lid = cpuid_get_clogid(CPU); /* Logical ID of CPU */ 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate for (i = 0; i < 18; i++) { 9380ac7d7d8Skucharsk uint64_t escr; 9390ac7d7d8Skucharsk 9407c478bd9Sstevel@tonic-gate if (cfgs[i] == NULL) 9417c478bd9Sstevel@tonic-gate continue; 9427c478bd9Sstevel@tonic-gate escr = (uint64_t)cfgs[i]->p4_escr; 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate if (cfgs[i]->p4_flags & P4_THIS_USR) 9457c478bd9Sstevel@tonic-gate escr |= (lid == 0) ? ESCR_T0_USR : ESCR_T1_USR; 9467c478bd9Sstevel@tonic-gate if (cfgs[i]->p4_flags & P4_THIS_SYS) 9477c478bd9Sstevel@tonic-gate escr |= (lid == 0) ? ESCR_T0_OS : ESCR_T1_OS; 9487c478bd9Sstevel@tonic-gate if (cfgs[i]->p4_flags & P4_SIBLING_USR) 9497c478bd9Sstevel@tonic-gate escr |= (lid == 0) ? ESCR_T1_USR : ESCR_T0_USR; 9507c478bd9Sstevel@tonic-gate if (cfgs[i]->p4_flags & P4_SIBLING_SYS) 9517c478bd9Sstevel@tonic-gate escr |= (lid == 0) ? ESCR_T1_OS : ESCR_T0_OS; 9527c478bd9Sstevel@tonic-gate 9530ac7d7d8Skucharsk wrmsr(p4_ctrs[i].pc_caddr, cfgs[i]->p4_rawpic); 9540ac7d7d8Skucharsk wrmsr(p4_escrs[cfgs[i]->p4_escr_ndx].pe_addr, escr); 9557c478bd9Sstevel@tonic-gate } 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate for (i = 0; i < 18; i++) { 9587c478bd9Sstevel@tonic-gate if (cfgs[i] == NULL) 9597c478bd9Sstevel@tonic-gate continue; 9607c478bd9Sstevel@tonic-gate cccr = (uint64_t)cfgs[i]->p4_cccr; 9617c478bd9Sstevel@tonic-gate /* 9627c478bd9Sstevel@tonic-gate * We always target the overflow interrupt at the 9637c478bd9Sstevel@tonic-gate * logical CPU which is doing the counting. 9647c478bd9Sstevel@tonic-gate */ 9657c478bd9Sstevel@tonic-gate if (cfgs[i]->p4_flags & P4_PMI) 9667c478bd9Sstevel@tonic-gate cccr |= (lid == 0) ? 9677c478bd9Sstevel@tonic-gate CCCR_OVF_PMI_T0 : CCCR_OVF_PMI_T1; 9680ac7d7d8Skucharsk wrmsr(p4_ctrs[i].pc_ctladdr, cccr); 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate } else { 9717c478bd9Sstevel@tonic-gate for (i = 0; i < 18; i++) { 9727c478bd9Sstevel@tonic-gate if (cfgs[i] == NULL) 9737c478bd9Sstevel@tonic-gate continue; 9740ac7d7d8Skucharsk wrmsr(p4_ctrs[i].pc_caddr, cfgs[i]->p4_rawpic); 9750ac7d7d8Skucharsk wrmsr(p4_escrs[cfgs[i]->p4_escr_ndx].pe_addr, 9760ac7d7d8Skucharsk (uint64_t)cfgs[i]->p4_escr); 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate for (i = 0; i < 18; i++) { 9807c478bd9Sstevel@tonic-gate if (cfgs[i] == NULL) 9817c478bd9Sstevel@tonic-gate continue; 9820ac7d7d8Skucharsk wrmsr(p4_ctrs[i].pc_ctladdr, 9830ac7d7d8Skucharsk (uint64_t)cfgs[i]->p4_cccr); 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate } 9867c478bd9Sstevel@tonic-gate } 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate static void 9897c478bd9Sstevel@tonic-gate p4_pcbe_allstop(void) 9907c478bd9Sstevel@tonic-gate { 9917c478bd9Sstevel@tonic-gate int i; 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate for (i = 0; i < 18; i++) 9940ac7d7d8Skucharsk wrmsr(p4_ctrs[i].pc_ctladdr, 0ULL); 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate setcr4(getcr4() & ~CR4_PCE); 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate static void 10017c478bd9Sstevel@tonic-gate p4_pcbe_sample(void *token) 10027c478bd9Sstevel@tonic-gate { 10037c478bd9Sstevel@tonic-gate p4_pcbe_config_t *cfgs[18]; 10047c478bd9Sstevel@tonic-gate uint64_t *addrs[18]; 10057c478bd9Sstevel@tonic-gate uint64_t curpic[18]; 10067c478bd9Sstevel@tonic-gate int64_t diff; 10077c478bd9Sstevel@tonic-gate int i; 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate for (i = 0; i < 18; i++) 10100ac7d7d8Skucharsk curpic[i] = rdmsr(p4_ctrs[i].pc_caddr); 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate build_cfgs(cfgs, addrs, token); 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate for (i = 0; i < 18; i++) { 10157c478bd9Sstevel@tonic-gate if (cfgs[i] == NULL) 10167c478bd9Sstevel@tonic-gate continue; 10177c478bd9Sstevel@tonic-gate diff = curpic[i] - cfgs[i]->p4_rawpic; 10187c478bd9Sstevel@tonic-gate if (diff < 0) 10197c478bd9Sstevel@tonic-gate diff += (1ll << 40); 10207c478bd9Sstevel@tonic-gate *addrs[i] += diff; 10217c478bd9Sstevel@tonic-gate DTRACE_PROBE4(p4__pcbe__sample, int, i, uint64_t, *addrs[i], 10227c478bd9Sstevel@tonic-gate uint64_t, curpic[i], uint64_t, cfgs[i]->p4_rawpic); 10237c478bd9Sstevel@tonic-gate cfgs[i]->p4_rawpic = *addrs[i] & MASK40; 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate static void 10287c478bd9Sstevel@tonic-gate p4_pcbe_free(void *config) 10297c478bd9Sstevel@tonic-gate { 10307c478bd9Sstevel@tonic-gate kmem_free(config, sizeof (p4_pcbe_config_t)); 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate static struct modlpcbe modlpcbe = { 10347c478bd9Sstevel@tonic-gate &mod_pcbeops, 1035820c9f58Skk208521 "Pentium 4 Performance Counters", 10367c478bd9Sstevel@tonic-gate &p4_pcbe_ops 10377c478bd9Sstevel@tonic-gate }; 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate static struct modlinkage modl = { 10407c478bd9Sstevel@tonic-gate MODREV_1, 10417c478bd9Sstevel@tonic-gate &modlpcbe, 10427c478bd9Sstevel@tonic-gate }; 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate int 10457c478bd9Sstevel@tonic-gate _init(void) 10467c478bd9Sstevel@tonic-gate { 10477c478bd9Sstevel@tonic-gate if (p4_pcbe_init() != 0) 10487c478bd9Sstevel@tonic-gate return (ENOTSUP); 10497c478bd9Sstevel@tonic-gate return (mod_install(&modl)); 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate int 10537c478bd9Sstevel@tonic-gate _fini(void) 10547c478bd9Sstevel@tonic-gate { 10557c478bd9Sstevel@tonic-gate return (mod_remove(&modl)); 10567c478bd9Sstevel@tonic-gate } 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate int 10597c478bd9Sstevel@tonic-gate _info(struct modinfo *mi) 10607c478bd9Sstevel@tonic-gate { 10617c478bd9Sstevel@tonic-gate return (mod_info(&modl, mi)); 10627c478bd9Sstevel@tonic-gate } 1063