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 53156Sgirish * Common Development and Distribution License (the "License"). 63156Sgirish * 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 */ 211414Scindi 220Sstevel@tonic-gate /* 238803SJonathan.Haslam@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #include <sys/param.h> 280Sstevel@tonic-gate #include <sys/thread.h> 290Sstevel@tonic-gate #include <sys/cpuvar.h> 300Sstevel@tonic-gate #include <sys/inttypes.h> 310Sstevel@tonic-gate #include <sys/cmn_err.h> 320Sstevel@tonic-gate #include <sys/time.h> 336275Strevtom #include <sys/ksynch.h> 340Sstevel@tonic-gate #include <sys/systm.h> 350Sstevel@tonic-gate #include <sys/kcpc.h> 360Sstevel@tonic-gate #include <sys/cpc_impl.h> 370Sstevel@tonic-gate #include <sys/cpc_pcbe.h> 380Sstevel@tonic-gate #include <sys/atomic.h> 390Sstevel@tonic-gate #include <sys/sunddi.h> 400Sstevel@tonic-gate #include <sys/modctl.h> 410Sstevel@tonic-gate #include <sys/sdt.h> 42*11389SAlexander.Kolbasov@Sun.COM #include <sys/archsystm.h> 43*11389SAlexander.Kolbasov@Sun.COM #include <sys/promif.h> 44*11389SAlexander.Kolbasov@Sun.COM #include <sys/x_call.h> 45*11389SAlexander.Kolbasov@Sun.COM #include <sys/cap_util.h> 460Sstevel@tonic-gate #if defined(__x86) 470Sstevel@tonic-gate #include <asm/clock.h> 48*11389SAlexander.Kolbasov@Sun.COM #include <sys/xc_levels.h> 490Sstevel@tonic-gate #endif 500Sstevel@tonic-gate 51*11389SAlexander.Kolbasov@Sun.COM static kmutex_t kcpc_ctx_llock[CPC_HASH_BUCKETS]; /* protects ctx_list */ 52*11389SAlexander.Kolbasov@Sun.COM static kcpc_ctx_t *kcpc_ctx_list[CPC_HASH_BUCKETS]; /* head of list */ 530Sstevel@tonic-gate 540Sstevel@tonic-gate 550Sstevel@tonic-gate krwlock_t kcpc_cpuctx_lock; /* lock for 'kcpc_cpuctx' below */ 560Sstevel@tonic-gate int kcpc_cpuctx; /* number of cpu-specific contexts */ 570Sstevel@tonic-gate 580Sstevel@tonic-gate int kcpc_counts_include_idle = 1; /* Project Private /etc/system variable */ 590Sstevel@tonic-gate 600Sstevel@tonic-gate /* 610Sstevel@tonic-gate * These are set when a PCBE module is loaded. 620Sstevel@tonic-gate */ 630Sstevel@tonic-gate uint_t cpc_ncounters = 0; 640Sstevel@tonic-gate pcbe_ops_t *pcbe_ops = NULL; 650Sstevel@tonic-gate 660Sstevel@tonic-gate /* 670Sstevel@tonic-gate * Statistics on (mis)behavior 680Sstevel@tonic-gate */ 690Sstevel@tonic-gate static uint32_t kcpc_intrctx_count; /* # overflows in an interrupt handler */ 700Sstevel@tonic-gate static uint32_t kcpc_nullctx_count; /* # overflows in a thread with no ctx */ 710Sstevel@tonic-gate 720Sstevel@tonic-gate /* 738803SJonathan.Haslam@Sun.COM * By setting 'kcpc_nullctx_panic' to 1, any overflow interrupts in a thread 748803SJonathan.Haslam@Sun.COM * with no valid context will result in a panic. 750Sstevel@tonic-gate */ 760Sstevel@tonic-gate static int kcpc_nullctx_panic = 0; 770Sstevel@tonic-gate 780Sstevel@tonic-gate static void kcpc_lwp_create(kthread_t *t, kthread_t *ct); 790Sstevel@tonic-gate static void kcpc_restore(kcpc_ctx_t *ctx); 800Sstevel@tonic-gate static void kcpc_save(kcpc_ctx_t *ctx); 810Sstevel@tonic-gate static void kcpc_ctx_clone(kcpc_ctx_t *ctx, kcpc_ctx_t *cctx); 820Sstevel@tonic-gate static int kcpc_tryassign(kcpc_set_t *set, int starting_req, int *scratch); 830Sstevel@tonic-gate static kcpc_set_t *kcpc_dup_set(kcpc_set_t *set); 84*11389SAlexander.Kolbasov@Sun.COM static kcpc_set_t *kcpc_set_create(kcpc_request_t *reqs, int nreqs, 85*11389SAlexander.Kolbasov@Sun.COM int set_flags, int kmem_flags); 86*11389SAlexander.Kolbasov@Sun.COM 87*11389SAlexander.Kolbasov@Sun.COM /* 88*11389SAlexander.Kolbasov@Sun.COM * Macros to manipulate context flags. All flag updates should use one of these 89*11389SAlexander.Kolbasov@Sun.COM * two macros 90*11389SAlexander.Kolbasov@Sun.COM * 91*11389SAlexander.Kolbasov@Sun.COM * Flags should be always be updated atomically since some of the updates are 92*11389SAlexander.Kolbasov@Sun.COM * not protected by locks. 93*11389SAlexander.Kolbasov@Sun.COM */ 94*11389SAlexander.Kolbasov@Sun.COM #define KCPC_CTX_FLAG_SET(ctx, flag) atomic_or_uint(&(ctx)->kc_flags, (flag)) 95*11389SAlexander.Kolbasov@Sun.COM #define KCPC_CTX_FLAG_CLR(ctx, flag) atomic_and_uint(&(ctx)->kc_flags, ~(flag)) 96*11389SAlexander.Kolbasov@Sun.COM 97*11389SAlexander.Kolbasov@Sun.COM /* 98*11389SAlexander.Kolbasov@Sun.COM * The IS_HIPIL() macro verifies that the code is executed either from a 99*11389SAlexander.Kolbasov@Sun.COM * cross-call or from high-PIL interrupt 100*11389SAlexander.Kolbasov@Sun.COM */ 101*11389SAlexander.Kolbasov@Sun.COM #ifdef DEBUG 102*11389SAlexander.Kolbasov@Sun.COM #define IS_HIPIL() (getpil() >= XCALL_PIL) 103*11389SAlexander.Kolbasov@Sun.COM #else 104*11389SAlexander.Kolbasov@Sun.COM #define IS_HIPIL() 105*11389SAlexander.Kolbasov@Sun.COM #endif /* DEBUG */ 106*11389SAlexander.Kolbasov@Sun.COM 107*11389SAlexander.Kolbasov@Sun.COM 108*11389SAlexander.Kolbasov@Sun.COM extern int kcpc_hw_load_pcbe(void); 109*11389SAlexander.Kolbasov@Sun.COM 110*11389SAlexander.Kolbasov@Sun.COM /* 111*11389SAlexander.Kolbasov@Sun.COM * Return value from kcpc_hw_load_pcbe() 112*11389SAlexander.Kolbasov@Sun.COM */ 113*11389SAlexander.Kolbasov@Sun.COM static int kcpc_pcbe_error = 0; 114*11389SAlexander.Kolbasov@Sun.COM 115*11389SAlexander.Kolbasov@Sun.COM /* 116*11389SAlexander.Kolbasov@Sun.COM * Perform one-time initialization of kcpc framework. 117*11389SAlexander.Kolbasov@Sun.COM * This function performs the initialization only the first time it is called. 118*11389SAlexander.Kolbasov@Sun.COM * It is safe to call it multiple times. 119*11389SAlexander.Kolbasov@Sun.COM */ 120*11389SAlexander.Kolbasov@Sun.COM int 121*11389SAlexander.Kolbasov@Sun.COM kcpc_init(void) 122*11389SAlexander.Kolbasov@Sun.COM { 123*11389SAlexander.Kolbasov@Sun.COM long hash; 124*11389SAlexander.Kolbasov@Sun.COM static uint32_t kcpc_initialized = 0; 125*11389SAlexander.Kolbasov@Sun.COM 126*11389SAlexander.Kolbasov@Sun.COM /* 127*11389SAlexander.Kolbasov@Sun.COM * We already tried loading platform pcbe module and failed 128*11389SAlexander.Kolbasov@Sun.COM */ 129*11389SAlexander.Kolbasov@Sun.COM if (kcpc_pcbe_error != 0) 130*11389SAlexander.Kolbasov@Sun.COM return (-1); 131*11389SAlexander.Kolbasov@Sun.COM 132*11389SAlexander.Kolbasov@Sun.COM /* 133*11389SAlexander.Kolbasov@Sun.COM * The kcpc framework should be initialized at most once 134*11389SAlexander.Kolbasov@Sun.COM */ 135*11389SAlexander.Kolbasov@Sun.COM if (atomic_cas_32(&kcpc_initialized, 0, 1) != 0) 136*11389SAlexander.Kolbasov@Sun.COM return (0); 137*11389SAlexander.Kolbasov@Sun.COM 138*11389SAlexander.Kolbasov@Sun.COM rw_init(&kcpc_cpuctx_lock, NULL, RW_DEFAULT, NULL); 139*11389SAlexander.Kolbasov@Sun.COM for (hash = 0; hash < CPC_HASH_BUCKETS; hash++) 140*11389SAlexander.Kolbasov@Sun.COM mutex_init(&kcpc_ctx_llock[hash], 141*11389SAlexander.Kolbasov@Sun.COM NULL, MUTEX_DRIVER, (void *)(uintptr_t)15); 142*11389SAlexander.Kolbasov@Sun.COM 143*11389SAlexander.Kolbasov@Sun.COM /* 144*11389SAlexander.Kolbasov@Sun.COM * Load platform-specific pcbe module 145*11389SAlexander.Kolbasov@Sun.COM */ 146*11389SAlexander.Kolbasov@Sun.COM kcpc_pcbe_error = kcpc_hw_load_pcbe(); 147*11389SAlexander.Kolbasov@Sun.COM 148*11389SAlexander.Kolbasov@Sun.COM return (kcpc_pcbe_error == 0 ? 0 : -1); 149*11389SAlexander.Kolbasov@Sun.COM } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate void 1520Sstevel@tonic-gate kcpc_register_pcbe(pcbe_ops_t *ops) 1530Sstevel@tonic-gate { 1540Sstevel@tonic-gate pcbe_ops = ops; 1550Sstevel@tonic-gate cpc_ncounters = pcbe_ops->pcbe_ncounters(); 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate 1588803SJonathan.Haslam@Sun.COM void 1598803SJonathan.Haslam@Sun.COM kcpc_register_dcpc(void (*func)(uint64_t)) 1608803SJonathan.Haslam@Sun.COM { 1618803SJonathan.Haslam@Sun.COM dtrace_cpc_fire = func; 1628803SJonathan.Haslam@Sun.COM } 1638803SJonathan.Haslam@Sun.COM 1648803SJonathan.Haslam@Sun.COM void 1658803SJonathan.Haslam@Sun.COM kcpc_unregister_dcpc(void) 1668803SJonathan.Haslam@Sun.COM { 1678803SJonathan.Haslam@Sun.COM dtrace_cpc_fire = NULL; 1688803SJonathan.Haslam@Sun.COM } 1698803SJonathan.Haslam@Sun.COM 1700Sstevel@tonic-gate int 1710Sstevel@tonic-gate kcpc_bind_cpu(kcpc_set_t *set, processorid_t cpuid, int *subcode) 1720Sstevel@tonic-gate { 1730Sstevel@tonic-gate cpu_t *cp; 1740Sstevel@tonic-gate kcpc_ctx_t *ctx; 1750Sstevel@tonic-gate int error; 176*11389SAlexander.Kolbasov@Sun.COM int save_spl; 1770Sstevel@tonic-gate 178*11389SAlexander.Kolbasov@Sun.COM ctx = kcpc_ctx_alloc(KM_SLEEP); 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate if (kcpc_assign_reqs(set, ctx) != 0) { 1810Sstevel@tonic-gate kcpc_ctx_free(ctx); 1820Sstevel@tonic-gate *subcode = CPC_RESOURCE_UNAVAIL; 1830Sstevel@tonic-gate return (EINVAL); 1840Sstevel@tonic-gate } 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate ctx->kc_cpuid = cpuid; 1870Sstevel@tonic-gate ctx->kc_thread = curthread; 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate set->ks_data = kmem_zalloc(set->ks_nreqs * sizeof (uint64_t), KM_SLEEP); 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate if ((error = kcpc_configure_reqs(ctx, set, subcode)) != 0) { 1920Sstevel@tonic-gate kmem_free(set->ks_data, set->ks_nreqs * sizeof (uint64_t)); 1930Sstevel@tonic-gate kcpc_ctx_free(ctx); 1940Sstevel@tonic-gate return (error); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate set->ks_ctx = ctx; 1980Sstevel@tonic-gate ctx->kc_set = set; 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate /* 2010Sstevel@tonic-gate * We must hold cpu_lock to prevent DR, offlining, or unbinding while 2020Sstevel@tonic-gate * we are manipulating the cpu_t and programming the hardware, else the 2030Sstevel@tonic-gate * the cpu_t could go away while we're looking at it. 2040Sstevel@tonic-gate */ 2050Sstevel@tonic-gate mutex_enter(&cpu_lock); 2060Sstevel@tonic-gate cp = cpu_get(cpuid); 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate if (cp == NULL) 2090Sstevel@tonic-gate /* 2100Sstevel@tonic-gate * The CPU could have been DRd out while we were getting set up. 2110Sstevel@tonic-gate */ 2120Sstevel@tonic-gate goto unbound; 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate mutex_enter(&cp->cpu_cpc_ctxlock); 215*11389SAlexander.Kolbasov@Sun.COM kpreempt_disable(); 216*11389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall(); 2170Sstevel@tonic-gate 218*11389SAlexander.Kolbasov@Sun.COM /* 219*11389SAlexander.Kolbasov@Sun.COM * Check to see whether counters for CPU already being used by someone 220*11389SAlexander.Kolbasov@Sun.COM * other than kernel for capacity and utilization (since kernel will 221*11389SAlexander.Kolbasov@Sun.COM * let go of counters for user in kcpc_program() below) 222*11389SAlexander.Kolbasov@Sun.COM */ 223*11389SAlexander.Kolbasov@Sun.COM if (cp->cpu_cpc_ctx != NULL && !CU_CPC_ON(cp)) { 2240Sstevel@tonic-gate /* 2250Sstevel@tonic-gate * If this CPU already has a bound set, return an error. 2260Sstevel@tonic-gate */ 227*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 228*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 2290Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock); 2300Sstevel@tonic-gate goto unbound; 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate if (curthread->t_bind_cpu != cpuid) { 234*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 235*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 2360Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock); 2370Sstevel@tonic-gate goto unbound; 2380Sstevel@tonic-gate } 2390Sstevel@tonic-gate 240*11389SAlexander.Kolbasov@Sun.COM kcpc_program(ctx, B_FALSE, B_TRUE); 241*11389SAlexander.Kolbasov@Sun.COM 242*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 2430Sstevel@tonic-gate kpreempt_enable(); 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock); 2460Sstevel@tonic-gate mutex_exit(&cpu_lock); 2470Sstevel@tonic-gate 2486275Strevtom mutex_enter(&set->ks_lock); 2496275Strevtom set->ks_state |= KCPC_SET_BOUND; 2506275Strevtom cv_signal(&set->ks_condv); 2516275Strevtom mutex_exit(&set->ks_lock); 2526275Strevtom 2530Sstevel@tonic-gate return (0); 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate unbound: 2560Sstevel@tonic-gate mutex_exit(&cpu_lock); 2570Sstevel@tonic-gate set->ks_ctx = NULL; 2580Sstevel@tonic-gate kmem_free(set->ks_data, set->ks_nreqs * sizeof (uint64_t)); 2590Sstevel@tonic-gate kcpc_ctx_free(ctx); 2600Sstevel@tonic-gate return (EAGAIN); 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate int 2640Sstevel@tonic-gate kcpc_bind_thread(kcpc_set_t *set, kthread_t *t, int *subcode) 2650Sstevel@tonic-gate { 2660Sstevel@tonic-gate kcpc_ctx_t *ctx; 2670Sstevel@tonic-gate int error; 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate /* 2700Sstevel@tonic-gate * Only one set is allowed per context, so ensure there is no 2710Sstevel@tonic-gate * existing context. 2720Sstevel@tonic-gate */ 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate if (t->t_cpc_ctx != NULL) 2750Sstevel@tonic-gate return (EEXIST); 2760Sstevel@tonic-gate 277*11389SAlexander.Kolbasov@Sun.COM ctx = kcpc_ctx_alloc(KM_SLEEP); 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate /* 2800Sstevel@tonic-gate * The context must begin life frozen until it has been properly 2810Sstevel@tonic-gate * programmed onto the hardware. This prevents the context ops from 2820Sstevel@tonic-gate * worrying about it until we're ready. 2830Sstevel@tonic-gate */ 284*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_FREEZE); 2850Sstevel@tonic-gate ctx->kc_hrtime = gethrtime(); 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate if (kcpc_assign_reqs(set, ctx) != 0) { 2880Sstevel@tonic-gate kcpc_ctx_free(ctx); 2890Sstevel@tonic-gate *subcode = CPC_RESOURCE_UNAVAIL; 2900Sstevel@tonic-gate return (EINVAL); 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate ctx->kc_cpuid = -1; 2940Sstevel@tonic-gate if (set->ks_flags & CPC_BIND_LWP_INHERIT) 295*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_LWPINHERIT); 2960Sstevel@tonic-gate ctx->kc_thread = t; 2970Sstevel@tonic-gate t->t_cpc_ctx = ctx; 2980Sstevel@tonic-gate /* 2990Sstevel@tonic-gate * Permit threads to look at their own hardware counters from userland. 3000Sstevel@tonic-gate */ 301*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_NONPRIV); 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate /* 3040Sstevel@tonic-gate * Create the data store for this set. 3050Sstevel@tonic-gate */ 3060Sstevel@tonic-gate set->ks_data = kmem_alloc(set->ks_nreqs * sizeof (uint64_t), KM_SLEEP); 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate if ((error = kcpc_configure_reqs(ctx, set, subcode)) != 0) { 3090Sstevel@tonic-gate kmem_free(set->ks_data, set->ks_nreqs * sizeof (uint64_t)); 3100Sstevel@tonic-gate kcpc_ctx_free(ctx); 3110Sstevel@tonic-gate t->t_cpc_ctx = NULL; 3120Sstevel@tonic-gate return (error); 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate set->ks_ctx = ctx; 3160Sstevel@tonic-gate ctx->kc_set = set; 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate /* 3190Sstevel@tonic-gate * Add a device context to the subject thread. 3200Sstevel@tonic-gate */ 3210Sstevel@tonic-gate installctx(t, ctx, kcpc_save, kcpc_restore, NULL, 3220Sstevel@tonic-gate kcpc_lwp_create, NULL, kcpc_free); 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate /* 3250Sstevel@tonic-gate * Ask the backend to program the hardware. 3260Sstevel@tonic-gate */ 3270Sstevel@tonic-gate if (t == curthread) { 328*11389SAlexander.Kolbasov@Sun.COM int save_spl; 329*11389SAlexander.Kolbasov@Sun.COM 3300Sstevel@tonic-gate kpreempt_disable(); 331*11389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall(); 332*11389SAlexander.Kolbasov@Sun.COM kcpc_program(ctx, B_TRUE, B_TRUE); 333*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 3340Sstevel@tonic-gate kpreempt_enable(); 335*11389SAlexander.Kolbasov@Sun.COM } else { 3360Sstevel@tonic-gate /* 3370Sstevel@tonic-gate * Since we are the agent LWP, we know the victim LWP is stopped 3380Sstevel@tonic-gate * until we're done here; no need to worry about preemption or 3390Sstevel@tonic-gate * migration here. We still use an atomic op to clear the flag 3400Sstevel@tonic-gate * to ensure the flags are always self-consistent; they can 3410Sstevel@tonic-gate * still be accessed from, for instance, another CPU doing a 3420Sstevel@tonic-gate * kcpc_invalidate_all(). 3430Sstevel@tonic-gate */ 344*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_CLR(ctx, KCPC_CTX_FREEZE); 345*11389SAlexander.Kolbasov@Sun.COM } 3460Sstevel@tonic-gate 3476275Strevtom mutex_enter(&set->ks_lock); 3486275Strevtom set->ks_state |= KCPC_SET_BOUND; 3496275Strevtom cv_signal(&set->ks_condv); 3506275Strevtom mutex_exit(&set->ks_lock); 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate return (0); 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate /* 3560Sstevel@tonic-gate * Walk through each request in the set and ask the PCBE to configure a 3570Sstevel@tonic-gate * corresponding counter. 3580Sstevel@tonic-gate */ 3598803SJonathan.Haslam@Sun.COM int 3600Sstevel@tonic-gate kcpc_configure_reqs(kcpc_ctx_t *ctx, kcpc_set_t *set, int *subcode) 3610Sstevel@tonic-gate { 3620Sstevel@tonic-gate int i; 3630Sstevel@tonic-gate int ret; 3640Sstevel@tonic-gate kcpc_request_t *rp; 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++) { 3670Sstevel@tonic-gate int n; 3680Sstevel@tonic-gate rp = &set->ks_req[i]; 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate n = rp->kr_picnum; 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate ASSERT(n >= 0 && n < cpc_ncounters); 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate ASSERT(ctx->kc_pics[n].kp_req == NULL); 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate if (rp->kr_flags & CPC_OVF_NOTIFY_EMT) { 3770Sstevel@tonic-gate if ((pcbe_ops->pcbe_caps & CPC_CAP_OVERFLOW_INTERRUPT) 3780Sstevel@tonic-gate == 0) { 3790Sstevel@tonic-gate *subcode = -1; 3800Sstevel@tonic-gate return (ENOTSUP); 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate /* 3830Sstevel@tonic-gate * If any of the counters have requested overflow 3840Sstevel@tonic-gate * notification, we flag the context as being one that 3850Sstevel@tonic-gate * cares about overflow. 3860Sstevel@tonic-gate */ 387*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_SIGOVF); 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate rp->kr_config = NULL; 3910Sstevel@tonic-gate if ((ret = pcbe_ops->pcbe_configure(n, rp->kr_event, 3920Sstevel@tonic-gate rp->kr_preset, rp->kr_flags, rp->kr_nattrs, rp->kr_attr, 3930Sstevel@tonic-gate &(rp->kr_config), (void *)ctx)) != 0) { 3940Sstevel@tonic-gate kcpc_free_configs(set); 3950Sstevel@tonic-gate *subcode = ret; 3963732Sae112802 switch (ret) { 3973732Sae112802 case CPC_ATTR_REQUIRES_PRIVILEGE: 3983732Sae112802 case CPC_HV_NO_ACCESS: 3990Sstevel@tonic-gate return (EACCES); 4003732Sae112802 default: 4013732Sae112802 return (EINVAL); 4023732Sae112802 } 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate ctx->kc_pics[n].kp_req = rp; 4060Sstevel@tonic-gate rp->kr_picp = &ctx->kc_pics[n]; 4070Sstevel@tonic-gate rp->kr_data = set->ks_data + rp->kr_index; 4080Sstevel@tonic-gate *rp->kr_data = rp->kr_preset; 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate return (0); 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate 4148803SJonathan.Haslam@Sun.COM void 4150Sstevel@tonic-gate kcpc_free_configs(kcpc_set_t *set) 4160Sstevel@tonic-gate { 4170Sstevel@tonic-gate int i; 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++) 4200Sstevel@tonic-gate if (set->ks_req[i].kr_config != NULL) 4210Sstevel@tonic-gate pcbe_ops->pcbe_free(set->ks_req[i].kr_config); 4220Sstevel@tonic-gate } 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate /* 4250Sstevel@tonic-gate * buf points to a user address and the data should be copied out to that 4260Sstevel@tonic-gate * address in the current process. 4270Sstevel@tonic-gate */ 4280Sstevel@tonic-gate int 4290Sstevel@tonic-gate kcpc_sample(kcpc_set_t *set, uint64_t *buf, hrtime_t *hrtime, uint64_t *tick) 4300Sstevel@tonic-gate { 4310Sstevel@tonic-gate kcpc_ctx_t *ctx = set->ks_ctx; 432*11389SAlexander.Kolbasov@Sun.COM int save_spl; 4330Sstevel@tonic-gate 4346275Strevtom mutex_enter(&set->ks_lock); 4356275Strevtom if ((set->ks_state & KCPC_SET_BOUND) == 0) { 4366275Strevtom mutex_exit(&set->ks_lock); 4370Sstevel@tonic-gate return (EINVAL); 4386275Strevtom } 4396275Strevtom mutex_exit(&set->ks_lock); 4406275Strevtom 441*11389SAlexander.Kolbasov@Sun.COM /* 442*11389SAlexander.Kolbasov@Sun.COM * Kernel preemption must be disabled while reading the hardware regs, 443*11389SAlexander.Kolbasov@Sun.COM * and if this is a CPU-bound context, while checking the CPU binding of 444*11389SAlexander.Kolbasov@Sun.COM * the current thread. 445*11389SAlexander.Kolbasov@Sun.COM */ 446*11389SAlexander.Kolbasov@Sun.COM kpreempt_disable(); 447*11389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall(); 448*11389SAlexander.Kolbasov@Sun.COM 449*11389SAlexander.Kolbasov@Sun.COM if (ctx->kc_flags & KCPC_CTX_INVALID) { 450*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 451*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 4520Sstevel@tonic-gate return (EAGAIN); 453*11389SAlexander.Kolbasov@Sun.COM } 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate if ((ctx->kc_flags & KCPC_CTX_FREEZE) == 0) { 4560Sstevel@tonic-gate if (ctx->kc_cpuid != -1) { 4570Sstevel@tonic-gate if (curthread->t_bind_cpu != ctx->kc_cpuid) { 458*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 4590Sstevel@tonic-gate kpreempt_enable(); 4600Sstevel@tonic-gate return (EAGAIN); 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate if (ctx->kc_thread == curthread) { 465*11389SAlexander.Kolbasov@Sun.COM uint64_t curtick = KCPC_GET_TICK(); 466*11389SAlexander.Kolbasov@Sun.COM 467*11389SAlexander.Kolbasov@Sun.COM ctx->kc_hrtime = gethrtime_waitfree(); 4680Sstevel@tonic-gate pcbe_ops->pcbe_sample(ctx); 4690Sstevel@tonic-gate ctx->kc_vtick += curtick - ctx->kc_rawtick; 4700Sstevel@tonic-gate ctx->kc_rawtick = curtick; 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate 4733732Sae112802 /* 4743732Sae112802 * The config may have been invalidated by 4753732Sae112802 * the pcbe_sample op. 4763732Sae112802 */ 477*11389SAlexander.Kolbasov@Sun.COM if (ctx->kc_flags & KCPC_CTX_INVALID) { 478*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 479*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 4803732Sae112802 return (EAGAIN); 481*11389SAlexander.Kolbasov@Sun.COM } 482*11389SAlexander.Kolbasov@Sun.COM 4830Sstevel@tonic-gate } 4840Sstevel@tonic-gate 485*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 486*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 487*11389SAlexander.Kolbasov@Sun.COM 4880Sstevel@tonic-gate if (copyout(set->ks_data, buf, 4890Sstevel@tonic-gate set->ks_nreqs * sizeof (uint64_t)) == -1) 4900Sstevel@tonic-gate return (EFAULT); 4910Sstevel@tonic-gate if (copyout(&ctx->kc_hrtime, hrtime, sizeof (uint64_t)) == -1) 4920Sstevel@tonic-gate return (EFAULT); 4930Sstevel@tonic-gate if (copyout(&ctx->kc_vtick, tick, sizeof (uint64_t)) == -1) 4940Sstevel@tonic-gate return (EFAULT); 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate return (0); 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate /* 5000Sstevel@tonic-gate * Stop the counters on the CPU this context is bound to. 5010Sstevel@tonic-gate */ 5020Sstevel@tonic-gate static void 5030Sstevel@tonic-gate kcpc_stop_hw(kcpc_ctx_t *ctx) 5040Sstevel@tonic-gate { 5050Sstevel@tonic-gate cpu_t *cp; 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate kpreempt_disable(); 5080Sstevel@tonic-gate 509*11389SAlexander.Kolbasov@Sun.COM if (ctx->kc_cpuid == CPU->cpu_id) { 510*11389SAlexander.Kolbasov@Sun.COM cp = CPU; 511*11389SAlexander.Kolbasov@Sun.COM } else { 512*11389SAlexander.Kolbasov@Sun.COM cp = cpu_get(ctx->kc_cpuid); 513*11389SAlexander.Kolbasov@Sun.COM } 5140Sstevel@tonic-gate 515*11389SAlexander.Kolbasov@Sun.COM ASSERT(cp != NULL && cp->cpu_cpc_ctx == ctx); 516*11389SAlexander.Kolbasov@Sun.COM kcpc_cpu_stop(cp, B_FALSE); 517*11389SAlexander.Kolbasov@Sun.COM 5180Sstevel@tonic-gate kpreempt_enable(); 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate int 5220Sstevel@tonic-gate kcpc_unbind(kcpc_set_t *set) 5230Sstevel@tonic-gate { 5246275Strevtom kcpc_ctx_t *ctx; 5250Sstevel@tonic-gate kthread_t *t; 5260Sstevel@tonic-gate 5276275Strevtom /* 5286275Strevtom * We could be racing with the process's agent thread as it 5296275Strevtom * binds the set; we must wait for the set to finish binding 5306275Strevtom * before attempting to tear it down. 5316275Strevtom */ 5326275Strevtom mutex_enter(&set->ks_lock); 5336275Strevtom while ((set->ks_state & KCPC_SET_BOUND) == 0) 5346275Strevtom cv_wait(&set->ks_condv, &set->ks_lock); 5356275Strevtom mutex_exit(&set->ks_lock); 5360Sstevel@tonic-gate 5376275Strevtom ctx = set->ks_ctx; 5386275Strevtom 5396275Strevtom /* 5406275Strevtom * Use kc_lock to synchronize with kcpc_restore(). 5416275Strevtom */ 5426275Strevtom mutex_enter(&ctx->kc_lock); 543*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_INVALID); 5446275Strevtom mutex_exit(&ctx->kc_lock); 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate if (ctx->kc_cpuid == -1) { 5470Sstevel@tonic-gate t = ctx->kc_thread; 5480Sstevel@tonic-gate /* 5490Sstevel@tonic-gate * The context is thread-bound and therefore has a device 5500Sstevel@tonic-gate * context. It will be freed via removectx() calling 5510Sstevel@tonic-gate * freectx() calling kcpc_free(). 5520Sstevel@tonic-gate */ 553*11389SAlexander.Kolbasov@Sun.COM if (t == curthread) { 554*11389SAlexander.Kolbasov@Sun.COM int save_spl; 555*11389SAlexander.Kolbasov@Sun.COM 5560Sstevel@tonic-gate kpreempt_disable(); 557*11389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall(); 558*11389SAlexander.Kolbasov@Sun.COM if (!(ctx->kc_flags & KCPC_CTX_INVALID_STOPPED)) 559*11389SAlexander.Kolbasov@Sun.COM kcpc_unprogram(ctx, B_TRUE); 560*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 5610Sstevel@tonic-gate kpreempt_enable(); 5620Sstevel@tonic-gate } 5630Sstevel@tonic-gate #ifdef DEBUG 5640Sstevel@tonic-gate if (removectx(t, ctx, kcpc_save, kcpc_restore, NULL, 5650Sstevel@tonic-gate kcpc_lwp_create, NULL, kcpc_free) == 0) 5660Sstevel@tonic-gate panic("kcpc_unbind: context %p not preset on thread %p", 5677632SNick.Todd@Sun.COM (void *)ctx, (void *)t); 5680Sstevel@tonic-gate #else 5690Sstevel@tonic-gate (void) removectx(t, ctx, kcpc_save, kcpc_restore, NULL, 5700Sstevel@tonic-gate kcpc_lwp_create, NULL, kcpc_free); 5710Sstevel@tonic-gate #endif /* DEBUG */ 5720Sstevel@tonic-gate t->t_cpc_set = NULL; 5730Sstevel@tonic-gate t->t_cpc_ctx = NULL; 5740Sstevel@tonic-gate } else { 5750Sstevel@tonic-gate /* 5760Sstevel@tonic-gate * If we are unbinding a CPU-bound set from a remote CPU, the 5770Sstevel@tonic-gate * native CPU's idle thread could be in the midst of programming 5780Sstevel@tonic-gate * this context onto the CPU. We grab the context's lock here to 5790Sstevel@tonic-gate * ensure that the idle thread is done with it. When we release 5800Sstevel@tonic-gate * the lock, the CPU no longer has a context and the idle thread 5810Sstevel@tonic-gate * will move on. 5820Sstevel@tonic-gate * 5830Sstevel@tonic-gate * cpu_lock must be held to prevent the CPU from being DR'd out 5840Sstevel@tonic-gate * while we disassociate the context from the cpu_t. 5850Sstevel@tonic-gate */ 5860Sstevel@tonic-gate cpu_t *cp; 5870Sstevel@tonic-gate mutex_enter(&cpu_lock); 5880Sstevel@tonic-gate cp = cpu_get(ctx->kc_cpuid); 5890Sstevel@tonic-gate if (cp != NULL) { 5900Sstevel@tonic-gate /* 5910Sstevel@tonic-gate * The CPU may have been DR'd out of the system. 5920Sstevel@tonic-gate */ 5930Sstevel@tonic-gate mutex_enter(&cp->cpu_cpc_ctxlock); 5940Sstevel@tonic-gate if ((ctx->kc_flags & KCPC_CTX_INVALID_STOPPED) == 0) 5950Sstevel@tonic-gate kcpc_stop_hw(ctx); 5960Sstevel@tonic-gate ASSERT(ctx->kc_flags & KCPC_CTX_INVALID_STOPPED); 5970Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock); 5980Sstevel@tonic-gate } 5990Sstevel@tonic-gate mutex_exit(&cpu_lock); 6000Sstevel@tonic-gate if (ctx->kc_thread == curthread) { 6010Sstevel@tonic-gate kcpc_free(ctx, 0); 6020Sstevel@tonic-gate curthread->t_cpc_set = NULL; 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate return (0); 6070Sstevel@tonic-gate } 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate int 6100Sstevel@tonic-gate kcpc_preset(kcpc_set_t *set, int index, uint64_t preset) 6110Sstevel@tonic-gate { 6120Sstevel@tonic-gate int i; 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate ASSERT(set != NULL); 6156275Strevtom ASSERT(set->ks_state & KCPC_SET_BOUND); 6160Sstevel@tonic-gate ASSERT(set->ks_ctx->kc_thread == curthread); 6170Sstevel@tonic-gate ASSERT(set->ks_ctx->kc_cpuid == -1); 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate if (index < 0 || index >= set->ks_nreqs) 6200Sstevel@tonic-gate return (EINVAL); 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++) 6230Sstevel@tonic-gate if (set->ks_req[i].kr_index == index) 6240Sstevel@tonic-gate break; 6250Sstevel@tonic-gate ASSERT(i != set->ks_nreqs); 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate set->ks_req[i].kr_preset = preset; 6280Sstevel@tonic-gate return (0); 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate int 6320Sstevel@tonic-gate kcpc_restart(kcpc_set_t *set) 6330Sstevel@tonic-gate { 6340Sstevel@tonic-gate kcpc_ctx_t *ctx = set->ks_ctx; 6350Sstevel@tonic-gate int i; 636*11389SAlexander.Kolbasov@Sun.COM int save_spl; 6370Sstevel@tonic-gate 6386275Strevtom ASSERT(set->ks_state & KCPC_SET_BOUND); 6390Sstevel@tonic-gate ASSERT(ctx->kc_thread == curthread); 6400Sstevel@tonic-gate ASSERT(ctx->kc_cpuid == -1); 6410Sstevel@tonic-gate 642*11389SAlexander.Kolbasov@Sun.COM for (i = 0; i < set->ks_nreqs; i++) { 643*11389SAlexander.Kolbasov@Sun.COM *(set->ks_req[i].kr_data) = set->ks_req[i].kr_preset; 644*11389SAlexander.Kolbasov@Sun.COM pcbe_ops->pcbe_configure(0, NULL, set->ks_req[i].kr_preset, 645*11389SAlexander.Kolbasov@Sun.COM 0, 0, NULL, &set->ks_req[i].kr_config, NULL); 646*11389SAlexander.Kolbasov@Sun.COM } 647*11389SAlexander.Kolbasov@Sun.COM 6480Sstevel@tonic-gate kpreempt_disable(); 649*11389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall(); 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate /* 6520Sstevel@tonic-gate * If the user is doing this on a running set, make sure the counters 6530Sstevel@tonic-gate * are stopped first. 6540Sstevel@tonic-gate */ 6550Sstevel@tonic-gate if ((ctx->kc_flags & KCPC_CTX_FREEZE) == 0) 6560Sstevel@tonic-gate pcbe_ops->pcbe_allstop(); 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate /* 6590Sstevel@tonic-gate * Ask the backend to program the hardware. 6600Sstevel@tonic-gate */ 6610Sstevel@tonic-gate ctx->kc_rawtick = KCPC_GET_TICK(); 662*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_CLR(ctx, KCPC_CTX_FREEZE); 6630Sstevel@tonic-gate pcbe_ops->pcbe_program(ctx); 664*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 6650Sstevel@tonic-gate kpreempt_enable(); 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate return (0); 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate /* 6710Sstevel@tonic-gate * Caller must hold kcpc_cpuctx_lock. 6720Sstevel@tonic-gate */ 6730Sstevel@tonic-gate int 6740Sstevel@tonic-gate kcpc_enable(kthread_t *t, int cmd, int enable) 6750Sstevel@tonic-gate { 6760Sstevel@tonic-gate kcpc_ctx_t *ctx = t->t_cpc_ctx; 6770Sstevel@tonic-gate kcpc_set_t *set = t->t_cpc_set; 6780Sstevel@tonic-gate kcpc_set_t *newset; 6790Sstevel@tonic-gate int i; 6800Sstevel@tonic-gate int flag; 6810Sstevel@tonic-gate int err; 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate ASSERT(RW_READ_HELD(&kcpc_cpuctx_lock)); 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate if (ctx == NULL) { 6860Sstevel@tonic-gate /* 6870Sstevel@tonic-gate * This thread has a set but no context; it must be a 6880Sstevel@tonic-gate * CPU-bound set. 6890Sstevel@tonic-gate */ 6900Sstevel@tonic-gate ASSERT(t->t_cpc_set != NULL); 6910Sstevel@tonic-gate ASSERT(t->t_cpc_set->ks_ctx->kc_cpuid != -1); 6920Sstevel@tonic-gate return (EINVAL); 6930Sstevel@tonic-gate } else if (ctx->kc_flags & KCPC_CTX_INVALID) 6940Sstevel@tonic-gate return (EAGAIN); 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate if (cmd == CPC_ENABLE) { 6970Sstevel@tonic-gate if ((ctx->kc_flags & KCPC_CTX_FREEZE) == 0) 6980Sstevel@tonic-gate return (EINVAL); 6990Sstevel@tonic-gate kpreempt_disable(); 700*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_CLR(ctx, KCPC_CTX_FREEZE); 7010Sstevel@tonic-gate kcpc_restore(ctx); 7020Sstevel@tonic-gate kpreempt_enable(); 7030Sstevel@tonic-gate } else if (cmd == CPC_DISABLE) { 7040Sstevel@tonic-gate if (ctx->kc_flags & KCPC_CTX_FREEZE) 7050Sstevel@tonic-gate return (EINVAL); 7060Sstevel@tonic-gate kpreempt_disable(); 7070Sstevel@tonic-gate kcpc_save(ctx); 708*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_FREEZE); 7090Sstevel@tonic-gate kpreempt_enable(); 7100Sstevel@tonic-gate } else if (cmd == CPC_USR_EVENTS || cmd == CPC_SYS_EVENTS) { 7110Sstevel@tonic-gate /* 7120Sstevel@tonic-gate * Strategy for usr/sys: stop counters and update set's presets 7130Sstevel@tonic-gate * with current counter values, unbind, update requests with 7140Sstevel@tonic-gate * new config, then re-bind. 7150Sstevel@tonic-gate */ 7160Sstevel@tonic-gate flag = (cmd == CPC_USR_EVENTS) ? 7170Sstevel@tonic-gate CPC_COUNT_USER: CPC_COUNT_SYSTEM; 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate kpreempt_disable(); 720*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, 7210Sstevel@tonic-gate KCPC_CTX_INVALID | KCPC_CTX_INVALID_STOPPED); 7220Sstevel@tonic-gate pcbe_ops->pcbe_allstop(); 7230Sstevel@tonic-gate kpreempt_enable(); 724*11389SAlexander.Kolbasov@Sun.COM 7250Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++) { 7260Sstevel@tonic-gate set->ks_req[i].kr_preset = *(set->ks_req[i].kr_data); 7270Sstevel@tonic-gate if (enable) 7280Sstevel@tonic-gate set->ks_req[i].kr_flags |= flag; 7290Sstevel@tonic-gate else 7300Sstevel@tonic-gate set->ks_req[i].kr_flags &= ~flag; 7310Sstevel@tonic-gate } 7320Sstevel@tonic-gate newset = kcpc_dup_set(set); 7330Sstevel@tonic-gate if (kcpc_unbind(set) != 0) 7340Sstevel@tonic-gate return (EINVAL); 7350Sstevel@tonic-gate t->t_cpc_set = newset; 7360Sstevel@tonic-gate if (kcpc_bind_thread(newset, t, &err) != 0) { 7370Sstevel@tonic-gate t->t_cpc_set = NULL; 7380Sstevel@tonic-gate kcpc_free_set(newset); 7390Sstevel@tonic-gate return (EINVAL); 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate } else 7420Sstevel@tonic-gate return (EINVAL); 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate return (0); 7450Sstevel@tonic-gate } 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate /* 7480Sstevel@tonic-gate * Provide PCBEs with a way of obtaining the configs of every counter which will 7490Sstevel@tonic-gate * be programmed together. 7500Sstevel@tonic-gate * 7510Sstevel@tonic-gate * If current is NULL, provide the first config. 7520Sstevel@tonic-gate * 7530Sstevel@tonic-gate * If data != NULL, caller wants to know where the data store associated with 7540Sstevel@tonic-gate * the config we return is located. 7550Sstevel@tonic-gate */ 7560Sstevel@tonic-gate void * 7570Sstevel@tonic-gate kcpc_next_config(void *token, void *current, uint64_t **data) 7580Sstevel@tonic-gate { 7590Sstevel@tonic-gate int i; 7600Sstevel@tonic-gate kcpc_pic_t *pic; 7610Sstevel@tonic-gate kcpc_ctx_t *ctx = (kcpc_ctx_t *)token; 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate if (current == NULL) { 7640Sstevel@tonic-gate /* 7650Sstevel@tonic-gate * Client would like the first config, which may not be in 7660Sstevel@tonic-gate * counter 0; we need to search through the counters for the 7670Sstevel@tonic-gate * first config. 7680Sstevel@tonic-gate */ 7690Sstevel@tonic-gate for (i = 0; i < cpc_ncounters; i++) 7700Sstevel@tonic-gate if (ctx->kc_pics[i].kp_req != NULL) 7710Sstevel@tonic-gate break; 7720Sstevel@tonic-gate /* 7730Sstevel@tonic-gate * There are no counters configured for the given context. 7740Sstevel@tonic-gate */ 7750Sstevel@tonic-gate if (i == cpc_ncounters) 7760Sstevel@tonic-gate return (NULL); 7770Sstevel@tonic-gate } else { 7780Sstevel@tonic-gate /* 7790Sstevel@tonic-gate * There surely is a faster way to do this. 7800Sstevel@tonic-gate */ 7810Sstevel@tonic-gate for (i = 0; i < cpc_ncounters; i++) { 7820Sstevel@tonic-gate pic = &ctx->kc_pics[i]; 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate if (pic->kp_req != NULL && 7850Sstevel@tonic-gate current == pic->kp_req->kr_config) 7860Sstevel@tonic-gate break; 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate /* 7900Sstevel@tonic-gate * We found the current config at picnum i. Now search for the 7910Sstevel@tonic-gate * next configured PIC. 7920Sstevel@tonic-gate */ 7930Sstevel@tonic-gate for (i++; i < cpc_ncounters; i++) { 7940Sstevel@tonic-gate pic = &ctx->kc_pics[i]; 7950Sstevel@tonic-gate if (pic->kp_req != NULL) 7960Sstevel@tonic-gate break; 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate if (i == cpc_ncounters) 8000Sstevel@tonic-gate return (NULL); 8010Sstevel@tonic-gate } 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate if (data != NULL) { 8040Sstevel@tonic-gate *data = ctx->kc_pics[i].kp_req->kr_data; 8050Sstevel@tonic-gate } 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate return (ctx->kc_pics[i].kp_req->kr_config); 8080Sstevel@tonic-gate } 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate 8118803SJonathan.Haslam@Sun.COM kcpc_ctx_t * 812*11389SAlexander.Kolbasov@Sun.COM kcpc_ctx_alloc(int kmem_flags) 8130Sstevel@tonic-gate { 8140Sstevel@tonic-gate kcpc_ctx_t *ctx; 8150Sstevel@tonic-gate long hash; 8160Sstevel@tonic-gate 817*11389SAlexander.Kolbasov@Sun.COM ctx = (kcpc_ctx_t *)kmem_zalloc(sizeof (kcpc_ctx_t), kmem_flags); 818*11389SAlexander.Kolbasov@Sun.COM if (ctx == NULL) 819*11389SAlexander.Kolbasov@Sun.COM return (NULL); 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate hash = CPC_HASH_CTX(ctx); 8220Sstevel@tonic-gate mutex_enter(&kcpc_ctx_llock[hash]); 8230Sstevel@tonic-gate ctx->kc_next = kcpc_ctx_list[hash]; 8240Sstevel@tonic-gate kcpc_ctx_list[hash] = ctx; 8250Sstevel@tonic-gate mutex_exit(&kcpc_ctx_llock[hash]); 8260Sstevel@tonic-gate 8270Sstevel@tonic-gate ctx->kc_pics = (kcpc_pic_t *)kmem_zalloc(sizeof (kcpc_pic_t) * 8280Sstevel@tonic-gate cpc_ncounters, KM_SLEEP); 8290Sstevel@tonic-gate 8300Sstevel@tonic-gate ctx->kc_cpuid = -1; 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate return (ctx); 8330Sstevel@tonic-gate } 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate /* 8360Sstevel@tonic-gate * Copy set from ctx to the child context, cctx, if it has CPC_BIND_LWP_INHERIT 8370Sstevel@tonic-gate * in the flags. 8380Sstevel@tonic-gate */ 8390Sstevel@tonic-gate static void 8400Sstevel@tonic-gate kcpc_ctx_clone(kcpc_ctx_t *ctx, kcpc_ctx_t *cctx) 8410Sstevel@tonic-gate { 8420Sstevel@tonic-gate kcpc_set_t *ks = ctx->kc_set, *cks; 8430Sstevel@tonic-gate int i, j; 8440Sstevel@tonic-gate int code; 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate ASSERT(ks != NULL); 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate if ((ks->ks_flags & CPC_BIND_LWP_INHERIT) == 0) 8490Sstevel@tonic-gate return; 8500Sstevel@tonic-gate 8516275Strevtom cks = kmem_zalloc(sizeof (*cks), KM_SLEEP); 8526275Strevtom cks->ks_state &= ~KCPC_SET_BOUND; 8530Sstevel@tonic-gate cctx->kc_set = cks; 8540Sstevel@tonic-gate cks->ks_flags = ks->ks_flags; 8550Sstevel@tonic-gate cks->ks_nreqs = ks->ks_nreqs; 8560Sstevel@tonic-gate cks->ks_req = kmem_alloc(cks->ks_nreqs * 8570Sstevel@tonic-gate sizeof (kcpc_request_t), KM_SLEEP); 8580Sstevel@tonic-gate cks->ks_data = kmem_alloc(cks->ks_nreqs * sizeof (uint64_t), 8590Sstevel@tonic-gate KM_SLEEP); 8600Sstevel@tonic-gate cks->ks_ctx = cctx; 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate for (i = 0; i < cks->ks_nreqs; i++) { 8630Sstevel@tonic-gate cks->ks_req[i].kr_index = ks->ks_req[i].kr_index; 8640Sstevel@tonic-gate cks->ks_req[i].kr_picnum = ks->ks_req[i].kr_picnum; 8650Sstevel@tonic-gate (void) strncpy(cks->ks_req[i].kr_event, 8660Sstevel@tonic-gate ks->ks_req[i].kr_event, CPC_MAX_EVENT_LEN); 8670Sstevel@tonic-gate cks->ks_req[i].kr_preset = ks->ks_req[i].kr_preset; 8680Sstevel@tonic-gate cks->ks_req[i].kr_flags = ks->ks_req[i].kr_flags; 8690Sstevel@tonic-gate cks->ks_req[i].kr_nattrs = ks->ks_req[i].kr_nattrs; 8700Sstevel@tonic-gate if (ks->ks_req[i].kr_nattrs > 0) { 8710Sstevel@tonic-gate cks->ks_req[i].kr_attr = 8720Sstevel@tonic-gate kmem_alloc(ks->ks_req[i].kr_nattrs * 8735254Sgavinm sizeof (kcpc_attr_t), KM_SLEEP); 8740Sstevel@tonic-gate } 8750Sstevel@tonic-gate for (j = 0; j < ks->ks_req[i].kr_nattrs; j++) { 8760Sstevel@tonic-gate (void) strncpy(cks->ks_req[i].kr_attr[j].ka_name, 8770Sstevel@tonic-gate ks->ks_req[i].kr_attr[j].ka_name, 8780Sstevel@tonic-gate CPC_MAX_ATTR_LEN); 8790Sstevel@tonic-gate cks->ks_req[i].kr_attr[j].ka_val = 8800Sstevel@tonic-gate ks->ks_req[i].kr_attr[j].ka_val; 8810Sstevel@tonic-gate } 8820Sstevel@tonic-gate } 8830Sstevel@tonic-gate if (kcpc_configure_reqs(cctx, cks, &code) != 0) 8843732Sae112802 kcpc_invalidate_config(cctx); 8856275Strevtom 8866275Strevtom mutex_enter(&cks->ks_lock); 8876275Strevtom cks->ks_state |= KCPC_SET_BOUND; 8886275Strevtom cv_signal(&cks->ks_condv); 8896275Strevtom mutex_exit(&cks->ks_lock); 8900Sstevel@tonic-gate } 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate 8938803SJonathan.Haslam@Sun.COM void 8940Sstevel@tonic-gate kcpc_ctx_free(kcpc_ctx_t *ctx) 8950Sstevel@tonic-gate { 8960Sstevel@tonic-gate kcpc_ctx_t **loc; 8970Sstevel@tonic-gate long hash = CPC_HASH_CTX(ctx); 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate mutex_enter(&kcpc_ctx_llock[hash]); 9000Sstevel@tonic-gate loc = &kcpc_ctx_list[hash]; 9010Sstevel@tonic-gate ASSERT(*loc != NULL); 9020Sstevel@tonic-gate while (*loc != ctx) 9030Sstevel@tonic-gate loc = &(*loc)->kc_next; 9040Sstevel@tonic-gate *loc = ctx->kc_next; 9050Sstevel@tonic-gate mutex_exit(&kcpc_ctx_llock[hash]); 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate kmem_free(ctx->kc_pics, cpc_ncounters * sizeof (kcpc_pic_t)); 9086275Strevtom cv_destroy(&ctx->kc_condv); 9096275Strevtom mutex_destroy(&ctx->kc_lock); 9100Sstevel@tonic-gate kmem_free(ctx, sizeof (*ctx)); 9110Sstevel@tonic-gate } 9120Sstevel@tonic-gate 9130Sstevel@tonic-gate /* 9140Sstevel@tonic-gate * Generic interrupt handler used on hardware that generates 9150Sstevel@tonic-gate * overflow interrupts. 9160Sstevel@tonic-gate * 9170Sstevel@tonic-gate * Note: executed at high-level interrupt context! 9180Sstevel@tonic-gate */ 9190Sstevel@tonic-gate /*ARGSUSED*/ 9200Sstevel@tonic-gate kcpc_ctx_t * 9210Sstevel@tonic-gate kcpc_overflow_intr(caddr_t arg, uint64_t bitmap) 9220Sstevel@tonic-gate { 9230Sstevel@tonic-gate kcpc_ctx_t *ctx; 9240Sstevel@tonic-gate kthread_t *t = curthread; 9250Sstevel@tonic-gate int i; 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate /* 9280Sstevel@tonic-gate * On both x86 and UltraSPARC, we may deliver the high-level 9290Sstevel@tonic-gate * interrupt in kernel mode, just after we've started to run an 9300Sstevel@tonic-gate * interrupt thread. (That's because the hardware helpfully 9310Sstevel@tonic-gate * delivers the overflow interrupt some random number of cycles 9320Sstevel@tonic-gate * after the instruction that caused the overflow by which time 9330Sstevel@tonic-gate * we're in some part of the kernel, not necessarily running on 9340Sstevel@tonic-gate * the right thread). 9350Sstevel@tonic-gate * 9360Sstevel@tonic-gate * Check for this case here -- find the pinned thread 9370Sstevel@tonic-gate * that was running when the interrupt went off. 9380Sstevel@tonic-gate */ 9390Sstevel@tonic-gate if (t->t_flag & T_INTR_THREAD) { 9400Sstevel@tonic-gate klwp_t *lwp; 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate atomic_add_32(&kcpc_intrctx_count, 1); 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate /* 9450Sstevel@tonic-gate * Note that t_lwp is always set to point at the underlying 9460Sstevel@tonic-gate * thread, thus this will work in the presence of nested 9470Sstevel@tonic-gate * interrupts. 9480Sstevel@tonic-gate */ 9490Sstevel@tonic-gate ctx = NULL; 9500Sstevel@tonic-gate if ((lwp = t->t_lwp) != NULL) { 9510Sstevel@tonic-gate t = lwptot(lwp); 9520Sstevel@tonic-gate ctx = t->t_cpc_ctx; 9530Sstevel@tonic-gate } 9540Sstevel@tonic-gate } else 9550Sstevel@tonic-gate ctx = t->t_cpc_ctx; 9560Sstevel@tonic-gate 9570Sstevel@tonic-gate if (ctx == NULL) { 9580Sstevel@tonic-gate /* 9590Sstevel@tonic-gate * This can easily happen if we're using the counters in 9600Sstevel@tonic-gate * "shared" mode, for example, and an overflow interrupt 9610Sstevel@tonic-gate * occurs while we are running cpustat. In that case, the 9620Sstevel@tonic-gate * bound thread that has the context that belongs to this 9630Sstevel@tonic-gate * CPU is almost certainly sleeping (if it was running on 9640Sstevel@tonic-gate * the CPU we'd have found it above), and the actual 9650Sstevel@tonic-gate * interrupted thread has no knowledge of performance counters! 9660Sstevel@tonic-gate */ 9670Sstevel@tonic-gate ctx = curthread->t_cpu->cpu_cpc_ctx; 9680Sstevel@tonic-gate if (ctx != NULL) { 9690Sstevel@tonic-gate /* 9700Sstevel@tonic-gate * Return the bound context for this CPU to 9710Sstevel@tonic-gate * the interrupt handler so that it can synchronously 9720Sstevel@tonic-gate * sample the hardware counters and restart them. 9730Sstevel@tonic-gate */ 9740Sstevel@tonic-gate return (ctx); 9750Sstevel@tonic-gate } 9760Sstevel@tonic-gate 9770Sstevel@tonic-gate /* 9780Sstevel@tonic-gate * As long as the overflow interrupt really is delivered early 9790Sstevel@tonic-gate * enough after trapping into the kernel to avoid switching 9800Sstevel@tonic-gate * threads, we must always be able to find the cpc context, 9810Sstevel@tonic-gate * or something went terribly wrong i.e. we ended up 9820Sstevel@tonic-gate * running a passivated interrupt thread, a kernel 9830Sstevel@tonic-gate * thread or we interrupted idle, all of which are Very Bad. 9848803SJonathan.Haslam@Sun.COM * 9858803SJonathan.Haslam@Sun.COM * We also could end up here owing to an incredibly unlikely 9868803SJonathan.Haslam@Sun.COM * race condition that exists on x86 based architectures when 9878803SJonathan.Haslam@Sun.COM * the cpc provider is in use; overflow interrupts are directed 9888803SJonathan.Haslam@Sun.COM * to the cpc provider if the 'dtrace_cpc_in_use' variable is 9898803SJonathan.Haslam@Sun.COM * set when we enter the handler. This variable is unset after 9908803SJonathan.Haslam@Sun.COM * overflow interrupts have been disabled on all CPUs and all 9918803SJonathan.Haslam@Sun.COM * contexts have been torn down. To stop interrupts, the cpc 9928803SJonathan.Haslam@Sun.COM * provider issues a xcall to the remote CPU before it tears 9938803SJonathan.Haslam@Sun.COM * down that CPUs context. As high priority xcalls, on an x86 9948803SJonathan.Haslam@Sun.COM * architecture, execute at a higher PIL than this handler, it 9958803SJonathan.Haslam@Sun.COM * is possible (though extremely unlikely) that the xcall could 9968803SJonathan.Haslam@Sun.COM * interrupt the overflow handler before the handler has 9978803SJonathan.Haslam@Sun.COM * checked the 'dtrace_cpc_in_use' variable, stop the counters, 9988803SJonathan.Haslam@Sun.COM * return to the cpc provider which could then rip down 9998803SJonathan.Haslam@Sun.COM * contexts and unset 'dtrace_cpc_in_use' *before* the CPUs 10008803SJonathan.Haslam@Sun.COM * overflow handler has had a chance to check the variable. In 10018803SJonathan.Haslam@Sun.COM * that case, the handler would direct the overflow into this 10028803SJonathan.Haslam@Sun.COM * code and no valid context will be found. The default behavior 10038803SJonathan.Haslam@Sun.COM * when no valid context is found is now to shout a warning to 10048803SJonathan.Haslam@Sun.COM * the console and bump the 'kcpc_nullctx_count' variable. 10050Sstevel@tonic-gate */ 10060Sstevel@tonic-gate if (kcpc_nullctx_panic) 10070Sstevel@tonic-gate panic("null cpc context, thread %p", (void *)t); 1008*11389SAlexander.Kolbasov@Sun.COM #ifdef DEBUG 1009*11389SAlexander.Kolbasov@Sun.COM cmn_err(CE_NOTE, 10108803SJonathan.Haslam@Sun.COM "null cpc context found in overflow handler!\n"); 1011*11389SAlexander.Kolbasov@Sun.COM #endif 10120Sstevel@tonic-gate atomic_add_32(&kcpc_nullctx_count, 1); 10130Sstevel@tonic-gate } else if ((ctx->kc_flags & KCPC_CTX_INVALID) == 0) { 10140Sstevel@tonic-gate /* 10150Sstevel@tonic-gate * Schedule an ast to sample the counters, which will 10160Sstevel@tonic-gate * propagate any overflow into the virtualized performance 10170Sstevel@tonic-gate * counter(s), and may deliver a signal. 10180Sstevel@tonic-gate */ 10190Sstevel@tonic-gate ttolwp(t)->lwp_pcb.pcb_flags |= CPC_OVERFLOW; 10200Sstevel@tonic-gate /* 10210Sstevel@tonic-gate * If a counter has overflowed which was counting on behalf of 10220Sstevel@tonic-gate * a request which specified CPC_OVF_NOTIFY_EMT, send the 10230Sstevel@tonic-gate * process a signal. 10240Sstevel@tonic-gate */ 10250Sstevel@tonic-gate for (i = 0; i < cpc_ncounters; i++) { 10260Sstevel@tonic-gate if (ctx->kc_pics[i].kp_req != NULL && 10270Sstevel@tonic-gate bitmap & (1 << i) && 10280Sstevel@tonic-gate ctx->kc_pics[i].kp_req->kr_flags & 10290Sstevel@tonic-gate CPC_OVF_NOTIFY_EMT) { 10300Sstevel@tonic-gate /* 10310Sstevel@tonic-gate * A signal has been requested for this PIC, so 10320Sstevel@tonic-gate * so freeze the context. The interrupt handler 10330Sstevel@tonic-gate * has already stopped the counter hardware. 10340Sstevel@tonic-gate */ 1035*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_FREEZE); 10360Sstevel@tonic-gate atomic_or_uint(&ctx->kc_pics[i].kp_flags, 10370Sstevel@tonic-gate KCPC_PIC_OVERFLOWED); 10380Sstevel@tonic-gate } 10390Sstevel@tonic-gate } 10400Sstevel@tonic-gate aston(t); 1041*11389SAlexander.Kolbasov@Sun.COM } else if (ctx->kc_flags & KCPC_CTX_INVALID_STOPPED) { 1042*11389SAlexander.Kolbasov@Sun.COM /* 1043*11389SAlexander.Kolbasov@Sun.COM * Thread context is no longer valid, but here may be a valid 1044*11389SAlexander.Kolbasov@Sun.COM * CPU context. 1045*11389SAlexander.Kolbasov@Sun.COM */ 1046*11389SAlexander.Kolbasov@Sun.COM return (curthread->t_cpu->cpu_cpc_ctx); 10470Sstevel@tonic-gate } 1048*11389SAlexander.Kolbasov@Sun.COM 10490Sstevel@tonic-gate return (NULL); 10500Sstevel@tonic-gate } 10510Sstevel@tonic-gate 10520Sstevel@tonic-gate /* 10530Sstevel@tonic-gate * The current thread context had an overflow interrupt; we're 10540Sstevel@tonic-gate * executing here in high-level interrupt context. 10550Sstevel@tonic-gate */ 10560Sstevel@tonic-gate /*ARGSUSED*/ 10570Sstevel@tonic-gate uint_t 10580Sstevel@tonic-gate kcpc_hw_overflow_intr(caddr_t arg1, caddr_t arg2) 10590Sstevel@tonic-gate { 10608803SJonathan.Haslam@Sun.COM kcpc_ctx_t *ctx; 10618803SJonathan.Haslam@Sun.COM uint64_t bitmap; 10628803SJonathan.Haslam@Sun.COM uint8_t *state; 1063*11389SAlexander.Kolbasov@Sun.COM int save_spl; 10640Sstevel@tonic-gate 10650Sstevel@tonic-gate if (pcbe_ops == NULL || 10660Sstevel@tonic-gate (bitmap = pcbe_ops->pcbe_overflow_bitmap()) == 0) 10670Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 10683884Sha137994 10690Sstevel@tonic-gate /* 10700Sstevel@tonic-gate * Prevent any further interrupts. 10710Sstevel@tonic-gate */ 10720Sstevel@tonic-gate pcbe_ops->pcbe_allstop(); 10730Sstevel@tonic-gate 10748803SJonathan.Haslam@Sun.COM if (dtrace_cpc_in_use) { 10758803SJonathan.Haslam@Sun.COM state = &cpu_core[CPU->cpu_id].cpuc_dcpc_intr_state; 10768803SJonathan.Haslam@Sun.COM 10778803SJonathan.Haslam@Sun.COM /* 10788803SJonathan.Haslam@Sun.COM * Set the per-CPU state bit to indicate that we are currently 10798803SJonathan.Haslam@Sun.COM * processing an interrupt if it is currently free. Drop the 10808803SJonathan.Haslam@Sun.COM * interrupt if the state isn't free (i.e. a configuration 10818803SJonathan.Haslam@Sun.COM * event is taking place). 10828803SJonathan.Haslam@Sun.COM */ 10838803SJonathan.Haslam@Sun.COM if (atomic_cas_8(state, DCPC_INTR_FREE, 10848803SJonathan.Haslam@Sun.COM DCPC_INTR_PROCESSING) == DCPC_INTR_FREE) { 10858803SJonathan.Haslam@Sun.COM int i; 10868803SJonathan.Haslam@Sun.COM kcpc_request_t req; 10878803SJonathan.Haslam@Sun.COM 10888803SJonathan.Haslam@Sun.COM ASSERT(dtrace_cpc_fire != NULL); 10898803SJonathan.Haslam@Sun.COM 10908803SJonathan.Haslam@Sun.COM (*dtrace_cpc_fire)(bitmap); 10918803SJonathan.Haslam@Sun.COM 10928803SJonathan.Haslam@Sun.COM ctx = curthread->t_cpu->cpu_cpc_ctx; 1093*11389SAlexander.Kolbasov@Sun.COM if (ctx == NULL) { 1094*11389SAlexander.Kolbasov@Sun.COM #ifdef DEBUG 1095*11389SAlexander.Kolbasov@Sun.COM cmn_err(CE_NOTE, "null cpc context in" 1096*11389SAlexander.Kolbasov@Sun.COM "hardware overflow handler!\n"); 1097*11389SAlexander.Kolbasov@Sun.COM #endif 1098*11389SAlexander.Kolbasov@Sun.COM return (DDI_INTR_CLAIMED); 1099*11389SAlexander.Kolbasov@Sun.COM } 11008803SJonathan.Haslam@Sun.COM 11018803SJonathan.Haslam@Sun.COM /* Reset any counters that have overflowed */ 11028803SJonathan.Haslam@Sun.COM for (i = 0; i < ctx->kc_set->ks_nreqs; i++) { 11038803SJonathan.Haslam@Sun.COM req = ctx->kc_set->ks_req[i]; 11048803SJonathan.Haslam@Sun.COM 11058803SJonathan.Haslam@Sun.COM if (bitmap & (1 << req.kr_picnum)) { 11068803SJonathan.Haslam@Sun.COM pcbe_ops->pcbe_configure(req.kr_picnum, 11078803SJonathan.Haslam@Sun.COM req.kr_event, req.kr_preset, 11088803SJonathan.Haslam@Sun.COM req.kr_flags, req.kr_nattrs, 11098803SJonathan.Haslam@Sun.COM req.kr_attr, &(req.kr_config), 11108803SJonathan.Haslam@Sun.COM (void *)ctx); 11118803SJonathan.Haslam@Sun.COM } 11128803SJonathan.Haslam@Sun.COM } 11138803SJonathan.Haslam@Sun.COM pcbe_ops->pcbe_program(ctx); 11148803SJonathan.Haslam@Sun.COM 11158803SJonathan.Haslam@Sun.COM /* 11168803SJonathan.Haslam@Sun.COM * We've finished processing the interrupt so set 11178803SJonathan.Haslam@Sun.COM * the state back to free. 11188803SJonathan.Haslam@Sun.COM */ 11198803SJonathan.Haslam@Sun.COM cpu_core[CPU->cpu_id].cpuc_dcpc_intr_state = 11208803SJonathan.Haslam@Sun.COM DCPC_INTR_FREE; 11218803SJonathan.Haslam@Sun.COM membar_producer(); 11228803SJonathan.Haslam@Sun.COM } 11238803SJonathan.Haslam@Sun.COM return (DDI_INTR_CLAIMED); 11248803SJonathan.Haslam@Sun.COM } 11258803SJonathan.Haslam@Sun.COM 11260Sstevel@tonic-gate /* 11278803SJonathan.Haslam@Sun.COM * DTrace isn't involved so pass on accordingly. 11280Sstevel@tonic-gate * 11290Sstevel@tonic-gate * If the interrupt has occurred in the context of an lwp owning 11300Sstevel@tonic-gate * the counters, then the handler posts an AST to the lwp to 11310Sstevel@tonic-gate * trigger the actual sampling, and optionally deliver a signal or 11320Sstevel@tonic-gate * restart the counters, on the way out of the kernel using 11330Sstevel@tonic-gate * kcpc_hw_overflow_ast() (see below). 11340Sstevel@tonic-gate * 11350Sstevel@tonic-gate * On the other hand, if the handler returns the context to us 11360Sstevel@tonic-gate * directly, then it means that there are no other threads in 11370Sstevel@tonic-gate * the middle of updating it, no AST has been posted, and so we 11380Sstevel@tonic-gate * should sample the counters here, and restart them with no 11390Sstevel@tonic-gate * further fuss. 1140*11389SAlexander.Kolbasov@Sun.COM * 1141*11389SAlexander.Kolbasov@Sun.COM * The CPU's CPC context may disappear as a result of cross-call which 1142*11389SAlexander.Kolbasov@Sun.COM * has higher PIL on x86, so protect the context by raising PIL to the 1143*11389SAlexander.Kolbasov@Sun.COM * cross-call level. 11440Sstevel@tonic-gate */ 1145*11389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall(); 11460Sstevel@tonic-gate if ((ctx = kcpc_overflow_intr(arg1, bitmap)) != NULL) { 11470Sstevel@tonic-gate uint64_t curtick = KCPC_GET_TICK(); 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate ctx->kc_hrtime = gethrtime_waitfree(); 11500Sstevel@tonic-gate ctx->kc_vtick += curtick - ctx->kc_rawtick; 11510Sstevel@tonic-gate ctx->kc_rawtick = curtick; 11520Sstevel@tonic-gate pcbe_ops->pcbe_sample(ctx); 11530Sstevel@tonic-gate pcbe_ops->pcbe_program(ctx); 11540Sstevel@tonic-gate } 1155*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 11560Sstevel@tonic-gate 11570Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 11580Sstevel@tonic-gate } 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate /* 11610Sstevel@tonic-gate * Called from trap() when processing the ast posted by the high-level 11620Sstevel@tonic-gate * interrupt handler. 11630Sstevel@tonic-gate */ 11640Sstevel@tonic-gate int 11650Sstevel@tonic-gate kcpc_overflow_ast() 11660Sstevel@tonic-gate { 11670Sstevel@tonic-gate kcpc_ctx_t *ctx = curthread->t_cpc_ctx; 11680Sstevel@tonic-gate int i; 11690Sstevel@tonic-gate int found = 0; 11700Sstevel@tonic-gate uint64_t curtick = KCPC_GET_TICK(); 11710Sstevel@tonic-gate 11720Sstevel@tonic-gate ASSERT(ctx != NULL); /* Beware of interrupt skid. */ 11730Sstevel@tonic-gate 11740Sstevel@tonic-gate /* 11750Sstevel@tonic-gate * An overflow happened: sample the context to ensure that 11760Sstevel@tonic-gate * the overflow is propagated into the upper bits of the 11770Sstevel@tonic-gate * virtualized 64-bit counter(s). 11780Sstevel@tonic-gate */ 11790Sstevel@tonic-gate kpreempt_disable(); 11800Sstevel@tonic-gate ctx->kc_hrtime = gethrtime_waitfree(); 11810Sstevel@tonic-gate pcbe_ops->pcbe_sample(ctx); 11820Sstevel@tonic-gate kpreempt_enable(); 11830Sstevel@tonic-gate 11840Sstevel@tonic-gate ctx->kc_vtick += curtick - ctx->kc_rawtick; 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate /* 11870Sstevel@tonic-gate * The interrupt handler has marked any pics with KCPC_PIC_OVERFLOWED 11880Sstevel@tonic-gate * if that pic generated an overflow and if the request it was counting 11890Sstevel@tonic-gate * on behalf of had CPC_OVERFLOW_REQUEST specified. We go through all 11900Sstevel@tonic-gate * pics in the context and clear the KCPC_PIC_OVERFLOWED flags. If we 11910Sstevel@tonic-gate * found any overflowed pics, keep the context frozen and return true 11920Sstevel@tonic-gate * (thus causing a signal to be sent). 11930Sstevel@tonic-gate */ 11940Sstevel@tonic-gate for (i = 0; i < cpc_ncounters; i++) { 11950Sstevel@tonic-gate if (ctx->kc_pics[i].kp_flags & KCPC_PIC_OVERFLOWED) { 11960Sstevel@tonic-gate atomic_and_uint(&ctx->kc_pics[i].kp_flags, 11970Sstevel@tonic-gate ~KCPC_PIC_OVERFLOWED); 11980Sstevel@tonic-gate found = 1; 11990Sstevel@tonic-gate } 12000Sstevel@tonic-gate } 12010Sstevel@tonic-gate if (found) 12020Sstevel@tonic-gate return (1); 12030Sstevel@tonic-gate 12040Sstevel@tonic-gate /* 12050Sstevel@tonic-gate * Otherwise, re-enable the counters and continue life as before. 12060Sstevel@tonic-gate */ 12070Sstevel@tonic-gate kpreempt_disable(); 1208*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_CLR(ctx, KCPC_CTX_FREEZE); 12090Sstevel@tonic-gate pcbe_ops->pcbe_program(ctx); 12100Sstevel@tonic-gate kpreempt_enable(); 12110Sstevel@tonic-gate return (0); 12120Sstevel@tonic-gate } 12130Sstevel@tonic-gate 12140Sstevel@tonic-gate /* 12150Sstevel@tonic-gate * Called when switching away from current thread. 12160Sstevel@tonic-gate */ 12170Sstevel@tonic-gate static void 12180Sstevel@tonic-gate kcpc_save(kcpc_ctx_t *ctx) 12190Sstevel@tonic-gate { 1220*11389SAlexander.Kolbasov@Sun.COM int err; 1221*11389SAlexander.Kolbasov@Sun.COM int save_spl; 1222*11389SAlexander.Kolbasov@Sun.COM 1223*11389SAlexander.Kolbasov@Sun.COM kpreempt_disable(); 1224*11389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall(); 1225*11389SAlexander.Kolbasov@Sun.COM 12260Sstevel@tonic-gate if (ctx->kc_flags & KCPC_CTX_INVALID) { 1227*11389SAlexander.Kolbasov@Sun.COM if (ctx->kc_flags & KCPC_CTX_INVALID_STOPPED) { 1228*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 1229*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 12300Sstevel@tonic-gate return; 1231*11389SAlexander.Kolbasov@Sun.COM } 12320Sstevel@tonic-gate /* 12330Sstevel@tonic-gate * This context has been invalidated but the counters have not 12340Sstevel@tonic-gate * been stopped. Stop them here and mark the context stopped. 12350Sstevel@tonic-gate */ 1236*11389SAlexander.Kolbasov@Sun.COM kcpc_unprogram(ctx, B_TRUE); 1237*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 1238*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 12390Sstevel@tonic-gate return; 12400Sstevel@tonic-gate } 12410Sstevel@tonic-gate 12420Sstevel@tonic-gate pcbe_ops->pcbe_allstop(); 1243*11389SAlexander.Kolbasov@Sun.COM if (ctx->kc_flags & KCPC_CTX_FREEZE) { 1244*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 1245*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 12460Sstevel@tonic-gate return; 1247*11389SAlexander.Kolbasov@Sun.COM } 12480Sstevel@tonic-gate 12490Sstevel@tonic-gate /* 12500Sstevel@tonic-gate * Need to sample for all reqs into each req's current mpic. 12510Sstevel@tonic-gate */ 1252*11389SAlexander.Kolbasov@Sun.COM ctx->kc_hrtime = gethrtime_waitfree(); 12530Sstevel@tonic-gate ctx->kc_vtick += KCPC_GET_TICK() - ctx->kc_rawtick; 12540Sstevel@tonic-gate pcbe_ops->pcbe_sample(ctx); 1255*11389SAlexander.Kolbasov@Sun.COM 1256*11389SAlexander.Kolbasov@Sun.COM /* 1257*11389SAlexander.Kolbasov@Sun.COM * Program counter for measuring capacity and utilization since user 1258*11389SAlexander.Kolbasov@Sun.COM * thread isn't using counter anymore 1259*11389SAlexander.Kolbasov@Sun.COM */ 1260*11389SAlexander.Kolbasov@Sun.COM ASSERT(ctx->kc_cpuid == -1); 1261*11389SAlexander.Kolbasov@Sun.COM cu_cpc_program(CPU, &err); 1262*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 1263*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 12640Sstevel@tonic-gate } 12650Sstevel@tonic-gate 12660Sstevel@tonic-gate static void 12670Sstevel@tonic-gate kcpc_restore(kcpc_ctx_t *ctx) 12680Sstevel@tonic-gate { 1269*11389SAlexander.Kolbasov@Sun.COM int save_spl; 1270*11389SAlexander.Kolbasov@Sun.COM 12716275Strevtom mutex_enter(&ctx->kc_lock); 1272*11389SAlexander.Kolbasov@Sun.COM 12730Sstevel@tonic-gate if ((ctx->kc_flags & (KCPC_CTX_INVALID | KCPC_CTX_INVALID_STOPPED)) == 1274*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_INVALID) { 12750Sstevel@tonic-gate /* 12760Sstevel@tonic-gate * The context is invalidated but has not been marked stopped. 12770Sstevel@tonic-gate * We mark it as such here because we will not start the 12780Sstevel@tonic-gate * counters during this context switch. 12790Sstevel@tonic-gate */ 1280*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_INVALID_STOPPED); 1281*11389SAlexander.Kolbasov@Sun.COM } 12820Sstevel@tonic-gate 12836275Strevtom if (ctx->kc_flags & (KCPC_CTX_INVALID | KCPC_CTX_FREEZE)) { 12846275Strevtom mutex_exit(&ctx->kc_lock); 12850Sstevel@tonic-gate return; 12866275Strevtom } 12876275Strevtom 12886275Strevtom /* 12896275Strevtom * Set kc_flags to show that a kcpc_restore() is in progress to avoid 12906275Strevtom * ctx & set related memory objects being freed without us knowing. 12916275Strevtom * This can happen if an agent thread is executing a kcpc_unbind(), 12926275Strevtom * with this thread as the target, whilst we're concurrently doing a 12936275Strevtom * restorectx() during, for example, a proc_exit(). Effectively, by 12946275Strevtom * doing this, we're asking kcpc_free() to cv_wait() until 12956275Strevtom * kcpc_restore() has completed. 12966275Strevtom */ 1297*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_RESTORE); 12986275Strevtom mutex_exit(&ctx->kc_lock); 12990Sstevel@tonic-gate 13000Sstevel@tonic-gate /* 13010Sstevel@tonic-gate * While programming the hardware, the counters should be stopped. We 13020Sstevel@tonic-gate * don't do an explicit pcbe_allstop() here because they should have 13030Sstevel@tonic-gate * been stopped already by the last consumer. 13040Sstevel@tonic-gate */ 1305*11389SAlexander.Kolbasov@Sun.COM kpreempt_disable(); 1306*11389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall(); 1307*11389SAlexander.Kolbasov@Sun.COM kcpc_program(ctx, B_TRUE, B_TRUE); 1308*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 1309*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 13106275Strevtom 13116275Strevtom /* 13126275Strevtom * Wake the agent thread if it's waiting in kcpc_free(). 13136275Strevtom */ 13146275Strevtom mutex_enter(&ctx->kc_lock); 1315*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_CLR(ctx, KCPC_CTX_RESTORE); 13166275Strevtom cv_signal(&ctx->kc_condv); 13176275Strevtom mutex_exit(&ctx->kc_lock); 13180Sstevel@tonic-gate } 13190Sstevel@tonic-gate 13200Sstevel@tonic-gate /* 13210Sstevel@tonic-gate * If kcpc_counts_include_idle is set to 0 by the sys admin, we add the the 13220Sstevel@tonic-gate * following context operators to the idle thread on each CPU. They stop the 13230Sstevel@tonic-gate * counters when the idle thread is switched on, and they start them again when 13240Sstevel@tonic-gate * it is switched off. 13250Sstevel@tonic-gate */ 13260Sstevel@tonic-gate /*ARGSUSED*/ 13270Sstevel@tonic-gate void 13280Sstevel@tonic-gate kcpc_idle_save(struct cpu *cp) 13290Sstevel@tonic-gate { 13300Sstevel@tonic-gate /* 13310Sstevel@tonic-gate * The idle thread shouldn't be run anywhere else. 13320Sstevel@tonic-gate */ 13330Sstevel@tonic-gate ASSERT(CPU == cp); 13340Sstevel@tonic-gate 13350Sstevel@tonic-gate /* 13360Sstevel@tonic-gate * We must hold the CPU's context lock to ensure the context isn't freed 13370Sstevel@tonic-gate * while we're looking at it. 13380Sstevel@tonic-gate */ 13390Sstevel@tonic-gate mutex_enter(&cp->cpu_cpc_ctxlock); 13400Sstevel@tonic-gate 13410Sstevel@tonic-gate if ((cp->cpu_cpc_ctx == NULL) || 13420Sstevel@tonic-gate (cp->cpu_cpc_ctx->kc_flags & KCPC_CTX_INVALID)) { 13430Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock); 13440Sstevel@tonic-gate return; 13450Sstevel@tonic-gate } 13460Sstevel@tonic-gate 13470Sstevel@tonic-gate pcbe_ops->pcbe_program(cp->cpu_cpc_ctx); 13480Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock); 13490Sstevel@tonic-gate } 13500Sstevel@tonic-gate 13510Sstevel@tonic-gate void 13520Sstevel@tonic-gate kcpc_idle_restore(struct cpu *cp) 13530Sstevel@tonic-gate { 13540Sstevel@tonic-gate /* 13550Sstevel@tonic-gate * The idle thread shouldn't be run anywhere else. 13560Sstevel@tonic-gate */ 13570Sstevel@tonic-gate ASSERT(CPU == cp); 13580Sstevel@tonic-gate 13590Sstevel@tonic-gate /* 13600Sstevel@tonic-gate * We must hold the CPU's context lock to ensure the context isn't freed 13610Sstevel@tonic-gate * while we're looking at it. 13620Sstevel@tonic-gate */ 13630Sstevel@tonic-gate mutex_enter(&cp->cpu_cpc_ctxlock); 13640Sstevel@tonic-gate 13650Sstevel@tonic-gate if ((cp->cpu_cpc_ctx == NULL) || 13660Sstevel@tonic-gate (cp->cpu_cpc_ctx->kc_flags & KCPC_CTX_INVALID)) { 13670Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock); 13680Sstevel@tonic-gate return; 13690Sstevel@tonic-gate } 13700Sstevel@tonic-gate 13710Sstevel@tonic-gate pcbe_ops->pcbe_allstop(); 13720Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock); 13730Sstevel@tonic-gate } 13740Sstevel@tonic-gate 13750Sstevel@tonic-gate /*ARGSUSED*/ 13760Sstevel@tonic-gate static void 13770Sstevel@tonic-gate kcpc_lwp_create(kthread_t *t, kthread_t *ct) 13780Sstevel@tonic-gate { 13790Sstevel@tonic-gate kcpc_ctx_t *ctx = t->t_cpc_ctx, *cctx; 13800Sstevel@tonic-gate int i; 13810Sstevel@tonic-gate 13820Sstevel@tonic-gate if (ctx == NULL || (ctx->kc_flags & KCPC_CTX_LWPINHERIT) == 0) 13830Sstevel@tonic-gate return; 13840Sstevel@tonic-gate 13850Sstevel@tonic-gate rw_enter(&kcpc_cpuctx_lock, RW_READER); 13860Sstevel@tonic-gate if (ctx->kc_flags & KCPC_CTX_INVALID) { 13870Sstevel@tonic-gate rw_exit(&kcpc_cpuctx_lock); 13880Sstevel@tonic-gate return; 13890Sstevel@tonic-gate } 1390*11389SAlexander.Kolbasov@Sun.COM cctx = kcpc_ctx_alloc(KM_SLEEP); 13910Sstevel@tonic-gate kcpc_ctx_clone(ctx, cctx); 13920Sstevel@tonic-gate rw_exit(&kcpc_cpuctx_lock); 13930Sstevel@tonic-gate 13943732Sae112802 /* 13953732Sae112802 * Copy the parent context's kc_flags field, but don't overwrite 13963732Sae112802 * the child's in case it was modified during kcpc_ctx_clone. 13973732Sae112802 */ 1398*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(cctx, ctx->kc_flags); 13990Sstevel@tonic-gate cctx->kc_thread = ct; 14000Sstevel@tonic-gate cctx->kc_cpuid = -1; 14010Sstevel@tonic-gate ct->t_cpc_set = cctx->kc_set; 14020Sstevel@tonic-gate ct->t_cpc_ctx = cctx; 14030Sstevel@tonic-gate 14040Sstevel@tonic-gate if (cctx->kc_flags & KCPC_CTX_SIGOVF) { 14050Sstevel@tonic-gate kcpc_set_t *ks = cctx->kc_set; 14060Sstevel@tonic-gate /* 14070Sstevel@tonic-gate * Our contract with the user requires us to immediately send an 14080Sstevel@tonic-gate * overflow signal to all children if we have the LWPINHERIT 14090Sstevel@tonic-gate * and SIGOVF flags set. In addition, all counters should be 14100Sstevel@tonic-gate * set to UINT64_MAX, and their pic's overflow flag turned on 14110Sstevel@tonic-gate * so that our trap() processing knows to send a signal. 14120Sstevel@tonic-gate */ 1413*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_FREEZE); 14140Sstevel@tonic-gate for (i = 0; i < ks->ks_nreqs; i++) { 14150Sstevel@tonic-gate kcpc_request_t *kr = &ks->ks_req[i]; 14160Sstevel@tonic-gate 14170Sstevel@tonic-gate if (kr->kr_flags & CPC_OVF_NOTIFY_EMT) { 14180Sstevel@tonic-gate *(kr->kr_data) = UINT64_MAX; 1419*11389SAlexander.Kolbasov@Sun.COM atomic_or_uint(&kr->kr_picp->kp_flags, 1420*11389SAlexander.Kolbasov@Sun.COM KCPC_PIC_OVERFLOWED); 14210Sstevel@tonic-gate } 14220Sstevel@tonic-gate } 14230Sstevel@tonic-gate ttolwp(ct)->lwp_pcb.pcb_flags |= CPC_OVERFLOW; 14240Sstevel@tonic-gate aston(ct); 14250Sstevel@tonic-gate } 14260Sstevel@tonic-gate 14270Sstevel@tonic-gate installctx(ct, cctx, kcpc_save, kcpc_restore, 14280Sstevel@tonic-gate NULL, kcpc_lwp_create, NULL, kcpc_free); 14290Sstevel@tonic-gate } 14300Sstevel@tonic-gate 14310Sstevel@tonic-gate /* 14320Sstevel@tonic-gate * Counter Stoppage Theory 14330Sstevel@tonic-gate * 14340Sstevel@tonic-gate * The counters may need to be stopped properly at the following occasions: 14350Sstevel@tonic-gate * 14360Sstevel@tonic-gate * 1) An LWP exits. 14370Sstevel@tonic-gate * 2) A thread exits. 14380Sstevel@tonic-gate * 3) An LWP performs an exec(). 14390Sstevel@tonic-gate * 4) A bound set is unbound. 14400Sstevel@tonic-gate * 14410Sstevel@tonic-gate * In addition to stopping the counters, the CPC context (a kcpc_ctx_t) may need 14420Sstevel@tonic-gate * to be freed as well. 14430Sstevel@tonic-gate * 14440Sstevel@tonic-gate * Case 1: kcpc_passivate(), called via lwp_exit(), stops the counters. Later on 14450Sstevel@tonic-gate * when the thread is freed, kcpc_free(), called by freectx(), frees the 14460Sstevel@tonic-gate * context. 14470Sstevel@tonic-gate * 14480Sstevel@tonic-gate * Case 2: same as case 1 except kcpc_passivate is called from thread_exit(). 14490Sstevel@tonic-gate * 14500Sstevel@tonic-gate * Case 3: kcpc_free(), called via freectx() via exec(), recognizes that it has 14510Sstevel@tonic-gate * been called from exec. It stops the counters _and_ frees the context. 14520Sstevel@tonic-gate * 14530Sstevel@tonic-gate * Case 4: kcpc_unbind() stops the hardware _and_ frees the context. 14540Sstevel@tonic-gate * 14550Sstevel@tonic-gate * CPU-bound counters are always stopped via kcpc_unbind(). 14560Sstevel@tonic-gate */ 14570Sstevel@tonic-gate 14580Sstevel@tonic-gate /* 14590Sstevel@tonic-gate * We're being called to delete the context; we ensure that all associated data 14600Sstevel@tonic-gate * structures are freed, and that the hardware is passivated if this is an exec. 14610Sstevel@tonic-gate */ 14620Sstevel@tonic-gate 14630Sstevel@tonic-gate /*ARGSUSED*/ 1464*11389SAlexander.Kolbasov@Sun.COM void 14650Sstevel@tonic-gate kcpc_free(kcpc_ctx_t *ctx, int isexec) 14660Sstevel@tonic-gate { 14670Sstevel@tonic-gate int i; 14680Sstevel@tonic-gate kcpc_set_t *set = ctx->kc_set; 14690Sstevel@tonic-gate 14700Sstevel@tonic-gate ASSERT(set != NULL); 14710Sstevel@tonic-gate 14726275Strevtom /* 14736275Strevtom * Wait for kcpc_restore() to finish before we tear things down. 14746275Strevtom */ 14756275Strevtom mutex_enter(&ctx->kc_lock); 14766275Strevtom while (ctx->kc_flags & KCPC_CTX_RESTORE) 14776275Strevtom cv_wait(&ctx->kc_condv, &ctx->kc_lock); 1478*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_INVALID); 14796275Strevtom mutex_exit(&ctx->kc_lock); 14800Sstevel@tonic-gate 14810Sstevel@tonic-gate if (isexec) { 14820Sstevel@tonic-gate /* 14830Sstevel@tonic-gate * This thread is execing, and after the exec it should not have 14840Sstevel@tonic-gate * any performance counter context. Stop the counters properly 14850Sstevel@tonic-gate * here so the system isn't surprised by an overflow interrupt 14860Sstevel@tonic-gate * later. 14870Sstevel@tonic-gate */ 14880Sstevel@tonic-gate if (ctx->kc_cpuid != -1) { 14890Sstevel@tonic-gate cpu_t *cp; 14900Sstevel@tonic-gate /* 14910Sstevel@tonic-gate * CPU-bound context; stop the appropriate CPU's ctrs. 14920Sstevel@tonic-gate * Hold cpu_lock while examining the CPU to ensure it 14930Sstevel@tonic-gate * doesn't go away. 14940Sstevel@tonic-gate */ 14950Sstevel@tonic-gate mutex_enter(&cpu_lock); 14960Sstevel@tonic-gate cp = cpu_get(ctx->kc_cpuid); 14970Sstevel@tonic-gate /* 14980Sstevel@tonic-gate * The CPU could have been DR'd out, so only stop the 14990Sstevel@tonic-gate * CPU and clear its context pointer if the CPU still 15000Sstevel@tonic-gate * exists. 15010Sstevel@tonic-gate */ 15020Sstevel@tonic-gate if (cp != NULL) { 15030Sstevel@tonic-gate mutex_enter(&cp->cpu_cpc_ctxlock); 15040Sstevel@tonic-gate kcpc_stop_hw(ctx); 15050Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock); 15060Sstevel@tonic-gate } 15070Sstevel@tonic-gate mutex_exit(&cpu_lock); 15080Sstevel@tonic-gate ASSERT(curthread->t_cpc_ctx == NULL); 15090Sstevel@tonic-gate } else { 1510*11389SAlexander.Kolbasov@Sun.COM int save_spl; 1511*11389SAlexander.Kolbasov@Sun.COM 15120Sstevel@tonic-gate /* 15130Sstevel@tonic-gate * Thread-bound context; stop _this_ CPU's counters. 15140Sstevel@tonic-gate */ 15150Sstevel@tonic-gate kpreempt_disable(); 1516*11389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall(); 1517*11389SAlexander.Kolbasov@Sun.COM kcpc_unprogram(ctx, B_TRUE); 1518*11389SAlexander.Kolbasov@Sun.COM curthread->t_cpc_ctx = NULL; 1519*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 15200Sstevel@tonic-gate kpreempt_enable(); 15210Sstevel@tonic-gate } 15220Sstevel@tonic-gate 15230Sstevel@tonic-gate /* 15240Sstevel@tonic-gate * Since we are being called from an exec and we know that 15250Sstevel@tonic-gate * exec is not permitted via the agent thread, we should clean 15260Sstevel@tonic-gate * up this thread's CPC state completely, and not leave dangling 15270Sstevel@tonic-gate * CPC pointers behind. 15280Sstevel@tonic-gate */ 15290Sstevel@tonic-gate ASSERT(ctx->kc_thread == curthread); 15300Sstevel@tonic-gate curthread->t_cpc_set = NULL; 15310Sstevel@tonic-gate } 15320Sstevel@tonic-gate 15330Sstevel@tonic-gate /* 15340Sstevel@tonic-gate * Walk through each request in this context's set and free the PCBE's 15350Sstevel@tonic-gate * configuration if it exists. 15360Sstevel@tonic-gate */ 15370Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++) { 15380Sstevel@tonic-gate if (set->ks_req[i].kr_config != NULL) 15390Sstevel@tonic-gate pcbe_ops->pcbe_free(set->ks_req[i].kr_config); 15400Sstevel@tonic-gate } 15410Sstevel@tonic-gate 15420Sstevel@tonic-gate kmem_free(set->ks_data, set->ks_nreqs * sizeof (uint64_t)); 15430Sstevel@tonic-gate kcpc_ctx_free(ctx); 15440Sstevel@tonic-gate kcpc_free_set(set); 15450Sstevel@tonic-gate } 15460Sstevel@tonic-gate 15470Sstevel@tonic-gate /* 15480Sstevel@tonic-gate * Free the memory associated with a request set. 15490Sstevel@tonic-gate */ 15500Sstevel@tonic-gate void 15510Sstevel@tonic-gate kcpc_free_set(kcpc_set_t *set) 15520Sstevel@tonic-gate { 15530Sstevel@tonic-gate int i; 15540Sstevel@tonic-gate kcpc_request_t *req; 15550Sstevel@tonic-gate 15560Sstevel@tonic-gate ASSERT(set->ks_req != NULL); 15570Sstevel@tonic-gate 15580Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++) { 15590Sstevel@tonic-gate req = &set->ks_req[i]; 15600Sstevel@tonic-gate 15610Sstevel@tonic-gate if (req->kr_nattrs != 0) { 15620Sstevel@tonic-gate kmem_free(req->kr_attr, 15630Sstevel@tonic-gate req->kr_nattrs * sizeof (kcpc_attr_t)); 15640Sstevel@tonic-gate } 15650Sstevel@tonic-gate } 15660Sstevel@tonic-gate 15670Sstevel@tonic-gate kmem_free(set->ks_req, sizeof (kcpc_request_t) * set->ks_nreqs); 15686275Strevtom cv_destroy(&set->ks_condv); 15696275Strevtom mutex_destroy(&set->ks_lock); 15700Sstevel@tonic-gate kmem_free(set, sizeof (kcpc_set_t)); 15710Sstevel@tonic-gate } 15720Sstevel@tonic-gate 15730Sstevel@tonic-gate /* 15740Sstevel@tonic-gate * Grab every existing context and mark it as invalid. 15750Sstevel@tonic-gate */ 15760Sstevel@tonic-gate void 15770Sstevel@tonic-gate kcpc_invalidate_all(void) 15780Sstevel@tonic-gate { 15790Sstevel@tonic-gate kcpc_ctx_t *ctx; 15800Sstevel@tonic-gate long hash; 15810Sstevel@tonic-gate 15820Sstevel@tonic-gate for (hash = 0; hash < CPC_HASH_BUCKETS; hash++) { 15830Sstevel@tonic-gate mutex_enter(&kcpc_ctx_llock[hash]); 15840Sstevel@tonic-gate for (ctx = kcpc_ctx_list[hash]; ctx; ctx = ctx->kc_next) 1585*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_INVALID); 15860Sstevel@tonic-gate mutex_exit(&kcpc_ctx_llock[hash]); 15870Sstevel@tonic-gate } 15880Sstevel@tonic-gate } 15890Sstevel@tonic-gate 15900Sstevel@tonic-gate /* 15913732Sae112802 * Interface for PCBEs to signal that an existing configuration has suddenly 15923732Sae112802 * become invalid. 15933732Sae112802 */ 15943732Sae112802 void 15953732Sae112802 kcpc_invalidate_config(void *token) 15963732Sae112802 { 15973732Sae112802 kcpc_ctx_t *ctx = token; 15983732Sae112802 15993732Sae112802 ASSERT(ctx != NULL); 16003732Sae112802 1601*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_INVALID); 16023732Sae112802 } 16033732Sae112802 16043732Sae112802 /* 16050Sstevel@tonic-gate * Called from lwp_exit() and thread_exit() 16060Sstevel@tonic-gate */ 16070Sstevel@tonic-gate void 16080Sstevel@tonic-gate kcpc_passivate(void) 16090Sstevel@tonic-gate { 16100Sstevel@tonic-gate kcpc_ctx_t *ctx = curthread->t_cpc_ctx; 16110Sstevel@tonic-gate kcpc_set_t *set = curthread->t_cpc_set; 1612*11389SAlexander.Kolbasov@Sun.COM int save_spl; 16130Sstevel@tonic-gate 16140Sstevel@tonic-gate if (set == NULL) 16150Sstevel@tonic-gate return; 16160Sstevel@tonic-gate 16170Sstevel@tonic-gate if (ctx == NULL) { 16180Sstevel@tonic-gate /* 16190Sstevel@tonic-gate * This thread has a set but no context; it must be a CPU-bound 16200Sstevel@tonic-gate * set. The hardware will be stopped via kcpc_unbind() when the 16210Sstevel@tonic-gate * process exits and closes its file descriptors with 16220Sstevel@tonic-gate * kcpc_close(). Our only job here is to clean up this thread's 16230Sstevel@tonic-gate * state; the set will be freed with the unbind(). 16240Sstevel@tonic-gate */ 16250Sstevel@tonic-gate (void) kcpc_unbind(set); 16260Sstevel@tonic-gate /* 16270Sstevel@tonic-gate * Unbinding a set belonging to the current thread should clear 16280Sstevel@tonic-gate * its set pointer. 16290Sstevel@tonic-gate */ 16300Sstevel@tonic-gate ASSERT(curthread->t_cpc_set == NULL); 16310Sstevel@tonic-gate return; 16320Sstevel@tonic-gate } 16330Sstevel@tonic-gate 1634*11389SAlexander.Kolbasov@Sun.COM kpreempt_disable(); 1635*11389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall(); 16360Sstevel@tonic-gate curthread->t_cpc_set = NULL; 16370Sstevel@tonic-gate 16380Sstevel@tonic-gate /* 16390Sstevel@tonic-gate * This thread/LWP is exiting but context switches will continue to 16400Sstevel@tonic-gate * happen for a bit as the exit proceeds. Kernel preemption must be 16410Sstevel@tonic-gate * disabled here to prevent a race between checking or setting the 16420Sstevel@tonic-gate * INVALID_STOPPED flag here and kcpc_restore() setting the flag during 16430Sstevel@tonic-gate * a context switch. 16440Sstevel@tonic-gate */ 16450Sstevel@tonic-gate if ((ctx->kc_flags & KCPC_CTX_INVALID_STOPPED) == 0) { 1646*11389SAlexander.Kolbasov@Sun.COM kcpc_unprogram(ctx, B_TRUE); 1647*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, 16480Sstevel@tonic-gate KCPC_CTX_INVALID | KCPC_CTX_INVALID_STOPPED); 16490Sstevel@tonic-gate } 1650*11389SAlexander.Kolbasov@Sun.COM 1651*11389SAlexander.Kolbasov@Sun.COM /* 1652*11389SAlexander.Kolbasov@Sun.COM * We're cleaning up after this thread; ensure there are no dangling 1653*11389SAlexander.Kolbasov@Sun.COM * CPC pointers left behind. The context and set will be freed by 1654*11389SAlexander.Kolbasov@Sun.COM * freectx(). 1655*11389SAlexander.Kolbasov@Sun.COM */ 1656*11389SAlexander.Kolbasov@Sun.COM curthread->t_cpc_ctx = NULL; 1657*11389SAlexander.Kolbasov@Sun.COM 1658*11389SAlexander.Kolbasov@Sun.COM splx(save_spl); 16590Sstevel@tonic-gate kpreempt_enable(); 16600Sstevel@tonic-gate } 16610Sstevel@tonic-gate 16620Sstevel@tonic-gate /* 16630Sstevel@tonic-gate * Assign the requests in the given set to the PICs in the context. 16640Sstevel@tonic-gate * Returns 0 if successful, -1 on failure. 16650Sstevel@tonic-gate */ 16660Sstevel@tonic-gate /*ARGSUSED*/ 16678803SJonathan.Haslam@Sun.COM int 16680Sstevel@tonic-gate kcpc_assign_reqs(kcpc_set_t *set, kcpc_ctx_t *ctx) 16690Sstevel@tonic-gate { 16700Sstevel@tonic-gate int i; 16710Sstevel@tonic-gate int *picnum_save; 16720Sstevel@tonic-gate 16730Sstevel@tonic-gate ASSERT(set->ks_nreqs <= cpc_ncounters); 16740Sstevel@tonic-gate 16750Sstevel@tonic-gate /* 16760Sstevel@tonic-gate * Provide kcpc_tryassign() with scratch space to avoid doing an 16770Sstevel@tonic-gate * alloc/free with every invocation. 16780Sstevel@tonic-gate */ 16790Sstevel@tonic-gate picnum_save = kmem_alloc(set->ks_nreqs * sizeof (int), KM_SLEEP); 16800Sstevel@tonic-gate /* 16810Sstevel@tonic-gate * kcpc_tryassign() blindly walks through each request in the set, 16820Sstevel@tonic-gate * seeing if a counter can count its event. If yes, it assigns that 16830Sstevel@tonic-gate * counter. However, that counter may have been the only capable counter 16840Sstevel@tonic-gate * for _another_ request's event. The solution is to try every possible 16850Sstevel@tonic-gate * request first. Note that this does not cover all solutions, as 16860Sstevel@tonic-gate * that would require all unique orderings of requests, an n^n operation 16870Sstevel@tonic-gate * which would be unacceptable for architectures with many counters. 16880Sstevel@tonic-gate */ 16890Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++) 16900Sstevel@tonic-gate if (kcpc_tryassign(set, i, picnum_save) == 0) 16910Sstevel@tonic-gate break; 16920Sstevel@tonic-gate 16930Sstevel@tonic-gate kmem_free(picnum_save, set->ks_nreqs * sizeof (int)); 16940Sstevel@tonic-gate if (i == set->ks_nreqs) 16950Sstevel@tonic-gate return (-1); 16960Sstevel@tonic-gate return (0); 16970Sstevel@tonic-gate } 16980Sstevel@tonic-gate 16990Sstevel@tonic-gate static int 17000Sstevel@tonic-gate kcpc_tryassign(kcpc_set_t *set, int starting_req, int *scratch) 17010Sstevel@tonic-gate { 17020Sstevel@tonic-gate int i; 17030Sstevel@tonic-gate int j; 17040Sstevel@tonic-gate uint64_t bitmap = 0, resmap = 0; 17050Sstevel@tonic-gate uint64_t ctrmap; 17060Sstevel@tonic-gate 17070Sstevel@tonic-gate /* 17080Sstevel@tonic-gate * We are attempting to assign the reqs to pics, but we may fail. If we 17090Sstevel@tonic-gate * fail, we need to restore the state of the requests to what it was 17100Sstevel@tonic-gate * when we found it, as some reqs may have been explicitly assigned to 17110Sstevel@tonic-gate * a specific PIC beforehand. We do this by snapshotting the assignments 17120Sstevel@tonic-gate * now and restoring from it later if we fail. 17130Sstevel@tonic-gate * 17140Sstevel@tonic-gate * Also we note here which counters have already been claimed by 17150Sstevel@tonic-gate * requests with explicit counter assignments. 17160Sstevel@tonic-gate */ 17170Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++) { 17180Sstevel@tonic-gate scratch[i] = set->ks_req[i].kr_picnum; 17190Sstevel@tonic-gate if (set->ks_req[i].kr_picnum != -1) 17200Sstevel@tonic-gate resmap |= (1 << set->ks_req[i].kr_picnum); 17210Sstevel@tonic-gate } 17220Sstevel@tonic-gate 17230Sstevel@tonic-gate /* 17240Sstevel@tonic-gate * Walk through requests assigning them to the first PIC that is 17250Sstevel@tonic-gate * capable. 17260Sstevel@tonic-gate */ 17270Sstevel@tonic-gate i = starting_req; 17280Sstevel@tonic-gate do { 17290Sstevel@tonic-gate if (set->ks_req[i].kr_picnum != -1) { 17300Sstevel@tonic-gate ASSERT((bitmap & (1 << set->ks_req[i].kr_picnum)) == 0); 17310Sstevel@tonic-gate bitmap |= (1 << set->ks_req[i].kr_picnum); 17320Sstevel@tonic-gate if (++i == set->ks_nreqs) 17330Sstevel@tonic-gate i = 0; 17340Sstevel@tonic-gate continue; 17350Sstevel@tonic-gate } 17360Sstevel@tonic-gate 17370Sstevel@tonic-gate ctrmap = pcbe_ops->pcbe_event_coverage(set->ks_req[i].kr_event); 17380Sstevel@tonic-gate for (j = 0; j < cpc_ncounters; j++) { 17390Sstevel@tonic-gate if (ctrmap & (1 << j) && (bitmap & (1 << j)) == 0 && 17400Sstevel@tonic-gate (resmap & (1 << j)) == 0) { 17410Sstevel@tonic-gate /* 17420Sstevel@tonic-gate * We can assign this counter because: 17430Sstevel@tonic-gate * 17440Sstevel@tonic-gate * 1. It can count the event (ctrmap) 17450Sstevel@tonic-gate * 2. It hasn't been assigned yet (bitmap) 17460Sstevel@tonic-gate * 3. It wasn't reserved by a request (resmap) 17470Sstevel@tonic-gate */ 17480Sstevel@tonic-gate bitmap |= (1 << j); 17490Sstevel@tonic-gate break; 17500Sstevel@tonic-gate } 17510Sstevel@tonic-gate } 17520Sstevel@tonic-gate if (j == cpc_ncounters) { 17530Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++) 17540Sstevel@tonic-gate set->ks_req[i].kr_picnum = scratch[i]; 17550Sstevel@tonic-gate return (-1); 17560Sstevel@tonic-gate } 17570Sstevel@tonic-gate set->ks_req[i].kr_picnum = j; 17580Sstevel@tonic-gate 17590Sstevel@tonic-gate if (++i == set->ks_nreqs) 17600Sstevel@tonic-gate i = 0; 17610Sstevel@tonic-gate } while (i != starting_req); 17620Sstevel@tonic-gate 17630Sstevel@tonic-gate return (0); 17640Sstevel@tonic-gate } 17650Sstevel@tonic-gate 17660Sstevel@tonic-gate kcpc_set_t * 17670Sstevel@tonic-gate kcpc_dup_set(kcpc_set_t *set) 17680Sstevel@tonic-gate { 17690Sstevel@tonic-gate kcpc_set_t *new; 17700Sstevel@tonic-gate int i; 17710Sstevel@tonic-gate int j; 17720Sstevel@tonic-gate 17736275Strevtom new = kmem_zalloc(sizeof (*new), KM_SLEEP); 17746275Strevtom new->ks_state &= ~KCPC_SET_BOUND; 17750Sstevel@tonic-gate new->ks_flags = set->ks_flags; 17760Sstevel@tonic-gate new->ks_nreqs = set->ks_nreqs; 17770Sstevel@tonic-gate new->ks_req = kmem_alloc(set->ks_nreqs * sizeof (kcpc_request_t), 17780Sstevel@tonic-gate KM_SLEEP); 17790Sstevel@tonic-gate new->ks_data = NULL; 17800Sstevel@tonic-gate new->ks_ctx = NULL; 17810Sstevel@tonic-gate 17820Sstevel@tonic-gate for (i = 0; i < new->ks_nreqs; i++) { 17830Sstevel@tonic-gate new->ks_req[i].kr_config = NULL; 17840Sstevel@tonic-gate new->ks_req[i].kr_index = set->ks_req[i].kr_index; 17850Sstevel@tonic-gate new->ks_req[i].kr_picnum = set->ks_req[i].kr_picnum; 17860Sstevel@tonic-gate new->ks_req[i].kr_picp = NULL; 17870Sstevel@tonic-gate new->ks_req[i].kr_data = NULL; 17880Sstevel@tonic-gate (void) strncpy(new->ks_req[i].kr_event, set->ks_req[i].kr_event, 17890Sstevel@tonic-gate CPC_MAX_EVENT_LEN); 17900Sstevel@tonic-gate new->ks_req[i].kr_preset = set->ks_req[i].kr_preset; 17910Sstevel@tonic-gate new->ks_req[i].kr_flags = set->ks_req[i].kr_flags; 17920Sstevel@tonic-gate new->ks_req[i].kr_nattrs = set->ks_req[i].kr_nattrs; 17930Sstevel@tonic-gate new->ks_req[i].kr_attr = kmem_alloc(new->ks_req[i].kr_nattrs * 17940Sstevel@tonic-gate sizeof (kcpc_attr_t), KM_SLEEP); 17950Sstevel@tonic-gate for (j = 0; j < new->ks_req[i].kr_nattrs; j++) { 17960Sstevel@tonic-gate new->ks_req[i].kr_attr[j].ka_val = 17970Sstevel@tonic-gate set->ks_req[i].kr_attr[j].ka_val; 17980Sstevel@tonic-gate (void) strncpy(new->ks_req[i].kr_attr[j].ka_name, 17990Sstevel@tonic-gate set->ks_req[i].kr_attr[j].ka_name, 18000Sstevel@tonic-gate CPC_MAX_ATTR_LEN); 18010Sstevel@tonic-gate } 18020Sstevel@tonic-gate } 18030Sstevel@tonic-gate 18040Sstevel@tonic-gate return (new); 18050Sstevel@tonic-gate } 18060Sstevel@tonic-gate 18070Sstevel@tonic-gate int 18080Sstevel@tonic-gate kcpc_allow_nonpriv(void *token) 18090Sstevel@tonic-gate { 18100Sstevel@tonic-gate return (((kcpc_ctx_t *)token)->kc_flags & KCPC_CTX_NONPRIV); 18110Sstevel@tonic-gate } 18120Sstevel@tonic-gate 18130Sstevel@tonic-gate void 18140Sstevel@tonic-gate kcpc_invalidate(kthread_t *t) 18150Sstevel@tonic-gate { 18160Sstevel@tonic-gate kcpc_ctx_t *ctx = t->t_cpc_ctx; 18170Sstevel@tonic-gate 18180Sstevel@tonic-gate if (ctx != NULL) 1819*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_INVALID); 18200Sstevel@tonic-gate } 18210Sstevel@tonic-gate 18220Sstevel@tonic-gate /* 18230Sstevel@tonic-gate * Given a PCBE ID, attempt to load a matching PCBE module. The strings given 18240Sstevel@tonic-gate * are used to construct PCBE names, starting with the most specific, 18250Sstevel@tonic-gate * "pcbe.first.second.third.fourth" and ending with the least specific, 18260Sstevel@tonic-gate * "pcbe.first". 18270Sstevel@tonic-gate * 18280Sstevel@tonic-gate * Returns 0 if a PCBE was successfully loaded and -1 upon error. 18290Sstevel@tonic-gate */ 18300Sstevel@tonic-gate int 18310Sstevel@tonic-gate kcpc_pcbe_tryload(const char *prefix, uint_t first, uint_t second, uint_t third) 18320Sstevel@tonic-gate { 18331414Scindi uint_t s[3]; 18340Sstevel@tonic-gate 18351414Scindi s[0] = first; 18361414Scindi s[1] = second; 18371414Scindi s[2] = third; 18380Sstevel@tonic-gate 18391414Scindi return (modload_qualified("pcbe", 18405254Sgavinm "pcbe", prefix, ".", s, 3, NULL) < 0 ? -1 : 0); 18410Sstevel@tonic-gate } 18428803SJonathan.Haslam@Sun.COM 1843*11389SAlexander.Kolbasov@Sun.COM /* 1844*11389SAlexander.Kolbasov@Sun.COM * Create one or more CPC context for given CPU with specified counter event 1845*11389SAlexander.Kolbasov@Sun.COM * requests 1846*11389SAlexander.Kolbasov@Sun.COM * 1847*11389SAlexander.Kolbasov@Sun.COM * If number of requested counter events is less than or equal number of 1848*11389SAlexander.Kolbasov@Sun.COM * hardware counters on a CPU and can all be assigned to the counters on a CPU 1849*11389SAlexander.Kolbasov@Sun.COM * at the same time, then make one CPC context. 1850*11389SAlexander.Kolbasov@Sun.COM * 1851*11389SAlexander.Kolbasov@Sun.COM * Otherwise, multiple CPC contexts are created to allow multiplexing more 1852*11389SAlexander.Kolbasov@Sun.COM * counter events than existing counters onto the counters by iterating through 1853*11389SAlexander.Kolbasov@Sun.COM * all of the CPC contexts, programming the counters with each CPC context one 1854*11389SAlexander.Kolbasov@Sun.COM * at a time and measuring the resulting counter values. Each of the resulting 1855*11389SAlexander.Kolbasov@Sun.COM * CPC contexts contains some number of requested counter events less than or 1856*11389SAlexander.Kolbasov@Sun.COM * equal the number of counters on a CPU depending on whether all the counter 1857*11389SAlexander.Kolbasov@Sun.COM * events can be programmed on all the counters at the same time or not. 1858*11389SAlexander.Kolbasov@Sun.COM * 1859*11389SAlexander.Kolbasov@Sun.COM * Flags to kmem_{,z}alloc() are passed in as an argument to allow specifying 1860*11389SAlexander.Kolbasov@Sun.COM * whether memory allocation should be non-blocking or not. The code will try 1861*11389SAlexander.Kolbasov@Sun.COM * to allocate *whole* CPC contexts if possible. If there is any memory 1862*11389SAlexander.Kolbasov@Sun.COM * allocation failure during the allocations needed for a given CPC context, it 1863*11389SAlexander.Kolbasov@Sun.COM * will skip allocating that CPC context because it cannot allocate the whole 1864*11389SAlexander.Kolbasov@Sun.COM * thing. Thus, the only time that it will end up allocating none (ie. no CPC 1865*11389SAlexander.Kolbasov@Sun.COM * contexts whatsoever) is when it cannot even allocate *one* whole CPC context 1866*11389SAlexander.Kolbasov@Sun.COM * without a memory allocation failure occurring. 1867*11389SAlexander.Kolbasov@Sun.COM */ 1868*11389SAlexander.Kolbasov@Sun.COM int 1869*11389SAlexander.Kolbasov@Sun.COM kcpc_cpu_ctx_create(cpu_t *cp, kcpc_request_list_t *req_list, int kmem_flags, 1870*11389SAlexander.Kolbasov@Sun.COM kcpc_ctx_t ***ctx_ptr_array, size_t *ctx_ptr_array_sz) 1871*11389SAlexander.Kolbasov@Sun.COM { 1872*11389SAlexander.Kolbasov@Sun.COM kcpc_ctx_t **ctx_ptrs; 1873*11389SAlexander.Kolbasov@Sun.COM int nctx; 1874*11389SAlexander.Kolbasov@Sun.COM int nctx_ptrs; 1875*11389SAlexander.Kolbasov@Sun.COM int nreqs; 1876*11389SAlexander.Kolbasov@Sun.COM kcpc_request_t *reqs; 1877*11389SAlexander.Kolbasov@Sun.COM 1878*11389SAlexander.Kolbasov@Sun.COM if (cp == NULL || ctx_ptr_array == NULL || ctx_ptr_array_sz == NULL || 1879*11389SAlexander.Kolbasov@Sun.COM req_list == NULL || req_list->krl_cnt < 1) 1880*11389SAlexander.Kolbasov@Sun.COM return (-1); 1881*11389SAlexander.Kolbasov@Sun.COM 1882*11389SAlexander.Kolbasov@Sun.COM /* 1883*11389SAlexander.Kolbasov@Sun.COM * Allocate number of sets assuming that each set contains one and only 1884*11389SAlexander.Kolbasov@Sun.COM * one counter event request for each counter on a CPU 1885*11389SAlexander.Kolbasov@Sun.COM */ 1886*11389SAlexander.Kolbasov@Sun.COM nreqs = req_list->krl_cnt; 1887*11389SAlexander.Kolbasov@Sun.COM nctx_ptrs = (nreqs + cpc_ncounters - 1) / cpc_ncounters; 1888*11389SAlexander.Kolbasov@Sun.COM ctx_ptrs = kmem_zalloc(nctx_ptrs * sizeof (kcpc_ctx_t *), kmem_flags); 1889*11389SAlexander.Kolbasov@Sun.COM if (ctx_ptrs == NULL) 1890*11389SAlexander.Kolbasov@Sun.COM return (-2); 1891*11389SAlexander.Kolbasov@Sun.COM 1892*11389SAlexander.Kolbasov@Sun.COM /* 1893*11389SAlexander.Kolbasov@Sun.COM * Fill in sets of requests 1894*11389SAlexander.Kolbasov@Sun.COM */ 1895*11389SAlexander.Kolbasov@Sun.COM nctx = 0; 1896*11389SAlexander.Kolbasov@Sun.COM reqs = req_list->krl_list; 1897*11389SAlexander.Kolbasov@Sun.COM while (nreqs > 0) { 1898*11389SAlexander.Kolbasov@Sun.COM kcpc_ctx_t *ctx; 1899*11389SAlexander.Kolbasov@Sun.COM kcpc_set_t *set; 1900*11389SAlexander.Kolbasov@Sun.COM int subcode; 1901*11389SAlexander.Kolbasov@Sun.COM 1902*11389SAlexander.Kolbasov@Sun.COM /* 1903*11389SAlexander.Kolbasov@Sun.COM * Allocate CPC context and set for requested counter events 1904*11389SAlexander.Kolbasov@Sun.COM */ 1905*11389SAlexander.Kolbasov@Sun.COM ctx = kcpc_ctx_alloc(kmem_flags); 1906*11389SAlexander.Kolbasov@Sun.COM set = kcpc_set_create(reqs, nreqs, 0, kmem_flags); 1907*11389SAlexander.Kolbasov@Sun.COM if (set == NULL) { 1908*11389SAlexander.Kolbasov@Sun.COM kcpc_ctx_free(ctx); 1909*11389SAlexander.Kolbasov@Sun.COM break; 1910*11389SAlexander.Kolbasov@Sun.COM } 1911*11389SAlexander.Kolbasov@Sun.COM 1912*11389SAlexander.Kolbasov@Sun.COM /* 1913*11389SAlexander.Kolbasov@Sun.COM * Determine assignment of requested counter events to specific 1914*11389SAlexander.Kolbasov@Sun.COM * counters 1915*11389SAlexander.Kolbasov@Sun.COM */ 1916*11389SAlexander.Kolbasov@Sun.COM if (kcpc_assign_reqs(set, ctx) != 0) { 1917*11389SAlexander.Kolbasov@Sun.COM /* 1918*11389SAlexander.Kolbasov@Sun.COM * May not be able to assign requested counter events 1919*11389SAlexander.Kolbasov@Sun.COM * to all counters since all counters may not be able 1920*11389SAlexander.Kolbasov@Sun.COM * to do all events, so only do one counter event in 1921*11389SAlexander.Kolbasov@Sun.COM * set of counter requests when this happens since at 1922*11389SAlexander.Kolbasov@Sun.COM * least one of the counters must be able to do the 1923*11389SAlexander.Kolbasov@Sun.COM * event. 1924*11389SAlexander.Kolbasov@Sun.COM */ 1925*11389SAlexander.Kolbasov@Sun.COM kcpc_free_set(set); 1926*11389SAlexander.Kolbasov@Sun.COM set = kcpc_set_create(reqs, 1, 0, kmem_flags); 1927*11389SAlexander.Kolbasov@Sun.COM if (set == NULL) { 1928*11389SAlexander.Kolbasov@Sun.COM kcpc_ctx_free(ctx); 1929*11389SAlexander.Kolbasov@Sun.COM break; 1930*11389SAlexander.Kolbasov@Sun.COM } 1931*11389SAlexander.Kolbasov@Sun.COM if (kcpc_assign_reqs(set, ctx) != 0) { 1932*11389SAlexander.Kolbasov@Sun.COM #ifdef DEBUG 1933*11389SAlexander.Kolbasov@Sun.COM cmn_err(CE_NOTE, "!kcpc_cpu_ctx_create: can't " 1934*11389SAlexander.Kolbasov@Sun.COM "assign counter event %s!\n", 1935*11389SAlexander.Kolbasov@Sun.COM set->ks_req->kr_event); 1936*11389SAlexander.Kolbasov@Sun.COM #endif 1937*11389SAlexander.Kolbasov@Sun.COM kcpc_free_set(set); 1938*11389SAlexander.Kolbasov@Sun.COM kcpc_ctx_free(ctx); 1939*11389SAlexander.Kolbasov@Sun.COM reqs++; 1940*11389SAlexander.Kolbasov@Sun.COM nreqs--; 1941*11389SAlexander.Kolbasov@Sun.COM continue; 1942*11389SAlexander.Kolbasov@Sun.COM } 1943*11389SAlexander.Kolbasov@Sun.COM } 1944*11389SAlexander.Kolbasov@Sun.COM 1945*11389SAlexander.Kolbasov@Sun.COM /* 1946*11389SAlexander.Kolbasov@Sun.COM * Allocate memory needed to hold requested counter event data 1947*11389SAlexander.Kolbasov@Sun.COM */ 1948*11389SAlexander.Kolbasov@Sun.COM set->ks_data = kmem_zalloc(set->ks_nreqs * sizeof (uint64_t), 1949*11389SAlexander.Kolbasov@Sun.COM kmem_flags); 1950*11389SAlexander.Kolbasov@Sun.COM if (set->ks_data == NULL) { 1951*11389SAlexander.Kolbasov@Sun.COM kcpc_free_set(set); 1952*11389SAlexander.Kolbasov@Sun.COM kcpc_ctx_free(ctx); 1953*11389SAlexander.Kolbasov@Sun.COM break; 1954*11389SAlexander.Kolbasov@Sun.COM } 1955*11389SAlexander.Kolbasov@Sun.COM 1956*11389SAlexander.Kolbasov@Sun.COM /* 1957*11389SAlexander.Kolbasov@Sun.COM * Configure requested counter events 1958*11389SAlexander.Kolbasov@Sun.COM */ 1959*11389SAlexander.Kolbasov@Sun.COM if (kcpc_configure_reqs(ctx, set, &subcode) != 0) { 1960*11389SAlexander.Kolbasov@Sun.COM #ifdef DEBUG 1961*11389SAlexander.Kolbasov@Sun.COM cmn_err(CE_NOTE, 1962*11389SAlexander.Kolbasov@Sun.COM "!kcpc_cpu_ctx_create: can't configure " 1963*11389SAlexander.Kolbasov@Sun.COM "set of counter event requests!\n"); 1964*11389SAlexander.Kolbasov@Sun.COM #endif 1965*11389SAlexander.Kolbasov@Sun.COM reqs += set->ks_nreqs; 1966*11389SAlexander.Kolbasov@Sun.COM nreqs -= set->ks_nreqs; 1967*11389SAlexander.Kolbasov@Sun.COM kmem_free(set->ks_data, 1968*11389SAlexander.Kolbasov@Sun.COM set->ks_nreqs * sizeof (uint64_t)); 1969*11389SAlexander.Kolbasov@Sun.COM kcpc_free_set(set); 1970*11389SAlexander.Kolbasov@Sun.COM kcpc_ctx_free(ctx); 1971*11389SAlexander.Kolbasov@Sun.COM continue; 1972*11389SAlexander.Kolbasov@Sun.COM } 1973*11389SAlexander.Kolbasov@Sun.COM 1974*11389SAlexander.Kolbasov@Sun.COM /* 1975*11389SAlexander.Kolbasov@Sun.COM * Point set of counter event requests at this context and fill 1976*11389SAlexander.Kolbasov@Sun.COM * in CPC context 1977*11389SAlexander.Kolbasov@Sun.COM */ 1978*11389SAlexander.Kolbasov@Sun.COM set->ks_ctx = ctx; 1979*11389SAlexander.Kolbasov@Sun.COM ctx->kc_set = set; 1980*11389SAlexander.Kolbasov@Sun.COM ctx->kc_cpuid = cp->cpu_id; 1981*11389SAlexander.Kolbasov@Sun.COM ctx->kc_thread = curthread; 1982*11389SAlexander.Kolbasov@Sun.COM 1983*11389SAlexander.Kolbasov@Sun.COM ctx_ptrs[nctx] = ctx; 1984*11389SAlexander.Kolbasov@Sun.COM 1985*11389SAlexander.Kolbasov@Sun.COM /* 1986*11389SAlexander.Kolbasov@Sun.COM * Update requests and how many are left to be assigned to sets 1987*11389SAlexander.Kolbasov@Sun.COM */ 1988*11389SAlexander.Kolbasov@Sun.COM reqs += set->ks_nreqs; 1989*11389SAlexander.Kolbasov@Sun.COM nreqs -= set->ks_nreqs; 1990*11389SAlexander.Kolbasov@Sun.COM 1991*11389SAlexander.Kolbasov@Sun.COM /* 1992*11389SAlexander.Kolbasov@Sun.COM * Increment number of CPC contexts and allocate bigger array 1993*11389SAlexander.Kolbasov@Sun.COM * for context pointers as needed 1994*11389SAlexander.Kolbasov@Sun.COM */ 1995*11389SAlexander.Kolbasov@Sun.COM nctx++; 1996*11389SAlexander.Kolbasov@Sun.COM if (nctx >= nctx_ptrs) { 1997*11389SAlexander.Kolbasov@Sun.COM kcpc_ctx_t **new; 1998*11389SAlexander.Kolbasov@Sun.COM int new_cnt; 1999*11389SAlexander.Kolbasov@Sun.COM 2000*11389SAlexander.Kolbasov@Sun.COM /* 2001*11389SAlexander.Kolbasov@Sun.COM * Allocate more CPC contexts based on how many 2002*11389SAlexander.Kolbasov@Sun.COM * contexts allocated so far and how many counter 2003*11389SAlexander.Kolbasov@Sun.COM * requests left to assign 2004*11389SAlexander.Kolbasov@Sun.COM */ 2005*11389SAlexander.Kolbasov@Sun.COM new_cnt = nctx_ptrs + 2006*11389SAlexander.Kolbasov@Sun.COM ((nreqs + cpc_ncounters - 1) / cpc_ncounters); 2007*11389SAlexander.Kolbasov@Sun.COM new = kmem_zalloc(new_cnt * sizeof (kcpc_ctx_t *), 2008*11389SAlexander.Kolbasov@Sun.COM kmem_flags); 2009*11389SAlexander.Kolbasov@Sun.COM if (new == NULL) 2010*11389SAlexander.Kolbasov@Sun.COM break; 2011*11389SAlexander.Kolbasov@Sun.COM 2012*11389SAlexander.Kolbasov@Sun.COM /* 2013*11389SAlexander.Kolbasov@Sun.COM * Copy contents of old sets into new ones 2014*11389SAlexander.Kolbasov@Sun.COM */ 2015*11389SAlexander.Kolbasov@Sun.COM bcopy(ctx_ptrs, new, 2016*11389SAlexander.Kolbasov@Sun.COM nctx_ptrs * sizeof (kcpc_ctx_t *)); 2017*11389SAlexander.Kolbasov@Sun.COM 2018*11389SAlexander.Kolbasov@Sun.COM /* 2019*11389SAlexander.Kolbasov@Sun.COM * Free old array of context pointers and use newly 2020*11389SAlexander.Kolbasov@Sun.COM * allocated one instead now 2021*11389SAlexander.Kolbasov@Sun.COM */ 2022*11389SAlexander.Kolbasov@Sun.COM kmem_free(ctx_ptrs, nctx_ptrs * sizeof (kcpc_ctx_t *)); 2023*11389SAlexander.Kolbasov@Sun.COM ctx_ptrs = new; 2024*11389SAlexander.Kolbasov@Sun.COM nctx_ptrs = new_cnt; 2025*11389SAlexander.Kolbasov@Sun.COM } 2026*11389SAlexander.Kolbasov@Sun.COM } 2027*11389SAlexander.Kolbasov@Sun.COM 2028*11389SAlexander.Kolbasov@Sun.COM /* 2029*11389SAlexander.Kolbasov@Sun.COM * Return NULL if no CPC contexts filled in 2030*11389SAlexander.Kolbasov@Sun.COM */ 2031*11389SAlexander.Kolbasov@Sun.COM if (nctx == 0) { 2032*11389SAlexander.Kolbasov@Sun.COM kmem_free(ctx_ptrs, nctx_ptrs * sizeof (kcpc_ctx_t *)); 2033*11389SAlexander.Kolbasov@Sun.COM *ctx_ptr_array = NULL; 2034*11389SAlexander.Kolbasov@Sun.COM *ctx_ptr_array_sz = 0; 2035*11389SAlexander.Kolbasov@Sun.COM return (-2); 2036*11389SAlexander.Kolbasov@Sun.COM } 2037*11389SAlexander.Kolbasov@Sun.COM 2038*11389SAlexander.Kolbasov@Sun.COM *ctx_ptr_array = ctx_ptrs; 2039*11389SAlexander.Kolbasov@Sun.COM *ctx_ptr_array_sz = nctx_ptrs * sizeof (kcpc_ctx_t *); 2040*11389SAlexander.Kolbasov@Sun.COM return (nctx); 2041*11389SAlexander.Kolbasov@Sun.COM } 2042*11389SAlexander.Kolbasov@Sun.COM 2043*11389SAlexander.Kolbasov@Sun.COM /* 2044*11389SAlexander.Kolbasov@Sun.COM * Return whether PCBE supports given counter event 2045*11389SAlexander.Kolbasov@Sun.COM */ 2046*11389SAlexander.Kolbasov@Sun.COM boolean_t 2047*11389SAlexander.Kolbasov@Sun.COM kcpc_event_supported(char *event) 2048*11389SAlexander.Kolbasov@Sun.COM { 2049*11389SAlexander.Kolbasov@Sun.COM if (pcbe_ops == NULL || pcbe_ops->pcbe_event_coverage(event) == 0) 2050*11389SAlexander.Kolbasov@Sun.COM return (B_FALSE); 2051*11389SAlexander.Kolbasov@Sun.COM 2052*11389SAlexander.Kolbasov@Sun.COM return (B_TRUE); 2053*11389SAlexander.Kolbasov@Sun.COM } 2054*11389SAlexander.Kolbasov@Sun.COM 2055*11389SAlexander.Kolbasov@Sun.COM /* 2056*11389SAlexander.Kolbasov@Sun.COM * Program counters on current CPU with given CPC context 2057*11389SAlexander.Kolbasov@Sun.COM * 2058*11389SAlexander.Kolbasov@Sun.COM * If kernel is interposing on counters to measure hardware capacity and 2059*11389SAlexander.Kolbasov@Sun.COM * utilization, then unprogram counters for kernel *before* programming them 2060*11389SAlexander.Kolbasov@Sun.COM * with specified CPC context. 2061*11389SAlexander.Kolbasov@Sun.COM * 2062*11389SAlexander.Kolbasov@Sun.COM * kcpc_{program,unprogram}() may be called either directly by a thread running 2063*11389SAlexander.Kolbasov@Sun.COM * on the target CPU or from a cross-call from another CPU. To protect 2064*11389SAlexander.Kolbasov@Sun.COM * programming and unprogramming from being interrupted by cross-calls, callers 2065*11389SAlexander.Kolbasov@Sun.COM * who execute kcpc_{program,unprogram} should raise PIL to the level used by 2066*11389SAlexander.Kolbasov@Sun.COM * cross-calls. 2067*11389SAlexander.Kolbasov@Sun.COM */ 2068*11389SAlexander.Kolbasov@Sun.COM void 2069*11389SAlexander.Kolbasov@Sun.COM kcpc_program(kcpc_ctx_t *ctx, boolean_t for_thread, boolean_t cu_interpose) 2070*11389SAlexander.Kolbasov@Sun.COM { 2071*11389SAlexander.Kolbasov@Sun.COM int error; 2072*11389SAlexander.Kolbasov@Sun.COM 2073*11389SAlexander.Kolbasov@Sun.COM ASSERT(IS_HIPIL()); 2074*11389SAlexander.Kolbasov@Sun.COM 2075*11389SAlexander.Kolbasov@Sun.COM /* 2076*11389SAlexander.Kolbasov@Sun.COM * CPC context shouldn't be NULL, its CPU field should specify current 2077*11389SAlexander.Kolbasov@Sun.COM * CPU or be -1 to specify any CPU when the context is bound to a 2078*11389SAlexander.Kolbasov@Sun.COM * thread, and preemption should be disabled 2079*11389SAlexander.Kolbasov@Sun.COM */ 2080*11389SAlexander.Kolbasov@Sun.COM ASSERT(ctx != NULL && (ctx->kc_cpuid == CPU->cpu_id || 2081*11389SAlexander.Kolbasov@Sun.COM ctx->kc_cpuid == -1) && curthread->t_preempt > 0); 2082*11389SAlexander.Kolbasov@Sun.COM if (ctx == NULL || (ctx->kc_cpuid != CPU->cpu_id && 2083*11389SAlexander.Kolbasov@Sun.COM ctx->kc_cpuid != -1) || curthread->t_preempt < 1) 2084*11389SAlexander.Kolbasov@Sun.COM return; 2085*11389SAlexander.Kolbasov@Sun.COM 2086*11389SAlexander.Kolbasov@Sun.COM /* 2087*11389SAlexander.Kolbasov@Sun.COM * Unprogram counters for kernel measuring hardware capacity and 2088*11389SAlexander.Kolbasov@Sun.COM * utilization 2089*11389SAlexander.Kolbasov@Sun.COM */ 2090*11389SAlexander.Kolbasov@Sun.COM if (cu_interpose == B_TRUE) { 2091*11389SAlexander.Kolbasov@Sun.COM cu_cpc_unprogram(CPU, &error); 2092*11389SAlexander.Kolbasov@Sun.COM } else { 2093*11389SAlexander.Kolbasov@Sun.COM kcpc_set_t *set = ctx->kc_set; 2094*11389SAlexander.Kolbasov@Sun.COM int i; 2095*11389SAlexander.Kolbasov@Sun.COM 2096*11389SAlexander.Kolbasov@Sun.COM ASSERT(set != NULL); 2097*11389SAlexander.Kolbasov@Sun.COM 2098*11389SAlexander.Kolbasov@Sun.COM /* 2099*11389SAlexander.Kolbasov@Sun.COM * Since cu_interpose is false, we are programming CU context. 2100*11389SAlexander.Kolbasov@Sun.COM * In general, PCBE can continue from the state saved in the 2101*11389SAlexander.Kolbasov@Sun.COM * set, but it is not very reliable, so we start again from the 2102*11389SAlexander.Kolbasov@Sun.COM * preset value. 2103*11389SAlexander.Kolbasov@Sun.COM */ 2104*11389SAlexander.Kolbasov@Sun.COM for (i = 0; i < set->ks_nreqs; i++) { 2105*11389SAlexander.Kolbasov@Sun.COM /* 2106*11389SAlexander.Kolbasov@Sun.COM * Reset the virtual counter value to the preset value. 2107*11389SAlexander.Kolbasov@Sun.COM */ 2108*11389SAlexander.Kolbasov@Sun.COM *(set->ks_req[i].kr_data) = set->ks_req[i].kr_preset; 2109*11389SAlexander.Kolbasov@Sun.COM 2110*11389SAlexander.Kolbasov@Sun.COM /* 2111*11389SAlexander.Kolbasov@Sun.COM * Reset PCBE to the preset value. 2112*11389SAlexander.Kolbasov@Sun.COM */ 2113*11389SAlexander.Kolbasov@Sun.COM pcbe_ops->pcbe_configure(0, NULL, 2114*11389SAlexander.Kolbasov@Sun.COM set->ks_req[i].kr_preset, 2115*11389SAlexander.Kolbasov@Sun.COM 0, 0, NULL, &set->ks_req[i].kr_config, NULL); 2116*11389SAlexander.Kolbasov@Sun.COM } 2117*11389SAlexander.Kolbasov@Sun.COM } 2118*11389SAlexander.Kolbasov@Sun.COM 2119*11389SAlexander.Kolbasov@Sun.COM /* 2120*11389SAlexander.Kolbasov@Sun.COM * Program counters with specified CPC context 2121*11389SAlexander.Kolbasov@Sun.COM */ 2122*11389SAlexander.Kolbasov@Sun.COM ctx->kc_rawtick = KCPC_GET_TICK(); 2123*11389SAlexander.Kolbasov@Sun.COM pcbe_ops->pcbe_program(ctx); 2124*11389SAlexander.Kolbasov@Sun.COM 2125*11389SAlexander.Kolbasov@Sun.COM /* 2126*11389SAlexander.Kolbasov@Sun.COM * Denote that counters programmed for thread or CPU CPC context 2127*11389SAlexander.Kolbasov@Sun.COM * differently 2128*11389SAlexander.Kolbasov@Sun.COM */ 2129*11389SAlexander.Kolbasov@Sun.COM if (for_thread == B_TRUE) 2130*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_CLR(ctx, KCPC_CTX_FREEZE); 2131*11389SAlexander.Kolbasov@Sun.COM else 2132*11389SAlexander.Kolbasov@Sun.COM CPU->cpu_cpc_ctx = ctx; 2133*11389SAlexander.Kolbasov@Sun.COM } 2134*11389SAlexander.Kolbasov@Sun.COM 2135*11389SAlexander.Kolbasov@Sun.COM /* 2136*11389SAlexander.Kolbasov@Sun.COM * Unprogram counters with given CPC context on current CPU 2137*11389SAlexander.Kolbasov@Sun.COM * 2138*11389SAlexander.Kolbasov@Sun.COM * If kernel is interposing on counters to measure hardware capacity and 2139*11389SAlexander.Kolbasov@Sun.COM * utilization, then program counters for the kernel capacity and utilization 2140*11389SAlexander.Kolbasov@Sun.COM * *after* unprogramming them for given CPC context. 2141*11389SAlexander.Kolbasov@Sun.COM * 2142*11389SAlexander.Kolbasov@Sun.COM * See the comment for kcpc_program regarding the synchronization with 2143*11389SAlexander.Kolbasov@Sun.COM * cross-calls. 2144*11389SAlexander.Kolbasov@Sun.COM */ 2145*11389SAlexander.Kolbasov@Sun.COM void 2146*11389SAlexander.Kolbasov@Sun.COM kcpc_unprogram(kcpc_ctx_t *ctx, boolean_t cu_interpose) 2147*11389SAlexander.Kolbasov@Sun.COM { 2148*11389SAlexander.Kolbasov@Sun.COM int error; 2149*11389SAlexander.Kolbasov@Sun.COM 2150*11389SAlexander.Kolbasov@Sun.COM ASSERT(IS_HIPIL()); 2151*11389SAlexander.Kolbasov@Sun.COM 2152*11389SAlexander.Kolbasov@Sun.COM /* 2153*11389SAlexander.Kolbasov@Sun.COM * CPC context shouldn't be NULL, its CPU field should specify current 2154*11389SAlexander.Kolbasov@Sun.COM * CPU or be -1 to specify any CPU when the context is bound to a 2155*11389SAlexander.Kolbasov@Sun.COM * thread, and preemption should be disabled 2156*11389SAlexander.Kolbasov@Sun.COM */ 2157*11389SAlexander.Kolbasov@Sun.COM ASSERT(ctx != NULL && (ctx->kc_cpuid == CPU->cpu_id || 2158*11389SAlexander.Kolbasov@Sun.COM ctx->kc_cpuid == -1) && curthread->t_preempt > 0); 2159*11389SAlexander.Kolbasov@Sun.COM 2160*11389SAlexander.Kolbasov@Sun.COM if (ctx == NULL || (ctx->kc_cpuid != CPU->cpu_id && 2161*11389SAlexander.Kolbasov@Sun.COM ctx->kc_cpuid != -1) || curthread->t_preempt < 1 || 2162*11389SAlexander.Kolbasov@Sun.COM (ctx->kc_flags & KCPC_CTX_INVALID_STOPPED) != 0) { 2163*11389SAlexander.Kolbasov@Sun.COM return; 2164*11389SAlexander.Kolbasov@Sun.COM } 2165*11389SAlexander.Kolbasov@Sun.COM 2166*11389SAlexander.Kolbasov@Sun.COM /* 2167*11389SAlexander.Kolbasov@Sun.COM * Specified CPC context to be unprogrammed should be bound to current 2168*11389SAlexander.Kolbasov@Sun.COM * CPU or thread 2169*11389SAlexander.Kolbasov@Sun.COM */ 2170*11389SAlexander.Kolbasov@Sun.COM ASSERT(CPU->cpu_cpc_ctx == ctx || curthread->t_cpc_ctx == ctx); 2171*11389SAlexander.Kolbasov@Sun.COM 2172*11389SAlexander.Kolbasov@Sun.COM /* 2173*11389SAlexander.Kolbasov@Sun.COM * Stop counters 2174*11389SAlexander.Kolbasov@Sun.COM */ 2175*11389SAlexander.Kolbasov@Sun.COM pcbe_ops->pcbe_allstop(); 2176*11389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_INVALID_STOPPED); 2177*11389SAlexander.Kolbasov@Sun.COM 2178*11389SAlexander.Kolbasov@Sun.COM /* 2179*11389SAlexander.Kolbasov@Sun.COM * Allow kernel to interpose on counters and program them for its own 2180*11389SAlexander.Kolbasov@Sun.COM * use to measure hardware capacity and utilization if cu_interpose 2181*11389SAlexander.Kolbasov@Sun.COM * argument is true 2182*11389SAlexander.Kolbasov@Sun.COM */ 2183*11389SAlexander.Kolbasov@Sun.COM if (cu_interpose == B_TRUE) 2184*11389SAlexander.Kolbasov@Sun.COM cu_cpc_program(CPU, &error); 2185*11389SAlexander.Kolbasov@Sun.COM } 2186*11389SAlexander.Kolbasov@Sun.COM 2187*11389SAlexander.Kolbasov@Sun.COM /* 2188*11389SAlexander.Kolbasov@Sun.COM * Read CPU Performance Counter (CPC) on current CPU and call specified update 2189*11389SAlexander.Kolbasov@Sun.COM * routine with data for each counter event currently programmed on CPU 2190*11389SAlexander.Kolbasov@Sun.COM */ 2191*11389SAlexander.Kolbasov@Sun.COM int 2192*11389SAlexander.Kolbasov@Sun.COM kcpc_read(kcpc_update_func_t update_func) 2193*11389SAlexander.Kolbasov@Sun.COM { 2194*11389SAlexander.Kolbasov@Sun.COM kcpc_ctx_t *ctx; 2195*11389SAlexander.Kolbasov@Sun.COM int i; 2196*11389SAlexander.Kolbasov@Sun.COM kcpc_request_t *req; 2197*11389SAlexander.Kolbasov@Sun.COM int retval; 2198*11389SAlexander.Kolbasov@Sun.COM kcpc_set_t *set; 2199*11389SAlexander.Kolbasov@Sun.COM 2200*11389SAlexander.Kolbasov@Sun.COM ASSERT(IS_HIPIL()); 2201*11389SAlexander.Kolbasov@Sun.COM 2202*11389SAlexander.Kolbasov@Sun.COM /* 2203*11389SAlexander.Kolbasov@Sun.COM * Can't grab locks or block because may be called inside dispatcher 2204*11389SAlexander.Kolbasov@Sun.COM */ 2205*11389SAlexander.Kolbasov@Sun.COM kpreempt_disable(); 2206*11389SAlexander.Kolbasov@Sun.COM 2207*11389SAlexander.Kolbasov@Sun.COM ctx = CPU->cpu_cpc_ctx; 2208*11389SAlexander.Kolbasov@Sun.COM if (ctx == NULL) { 2209*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 2210*11389SAlexander.Kolbasov@Sun.COM return (0); 2211*11389SAlexander.Kolbasov@Sun.COM } 2212*11389SAlexander.Kolbasov@Sun.COM 2213*11389SAlexander.Kolbasov@Sun.COM /* 2214*11389SAlexander.Kolbasov@Sun.COM * Read counter data from current CPU 2215*11389SAlexander.Kolbasov@Sun.COM */ 2216*11389SAlexander.Kolbasov@Sun.COM pcbe_ops->pcbe_sample(ctx); 2217*11389SAlexander.Kolbasov@Sun.COM 2218*11389SAlexander.Kolbasov@Sun.COM set = ctx->kc_set; 2219*11389SAlexander.Kolbasov@Sun.COM if (set == NULL || set->ks_req == NULL) { 2220*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 2221*11389SAlexander.Kolbasov@Sun.COM return (0); 2222*11389SAlexander.Kolbasov@Sun.COM } 2223*11389SAlexander.Kolbasov@Sun.COM 2224*11389SAlexander.Kolbasov@Sun.COM /* 2225*11389SAlexander.Kolbasov@Sun.COM * Call update function with preset pointer and data for each CPC event 2226*11389SAlexander.Kolbasov@Sun.COM * request currently programmed on current CPU 2227*11389SAlexander.Kolbasov@Sun.COM */ 2228*11389SAlexander.Kolbasov@Sun.COM req = set->ks_req; 2229*11389SAlexander.Kolbasov@Sun.COM retval = 0; 2230*11389SAlexander.Kolbasov@Sun.COM for (i = 0; i < set->ks_nreqs; i++) { 2231*11389SAlexander.Kolbasov@Sun.COM int ret; 2232*11389SAlexander.Kolbasov@Sun.COM 2233*11389SAlexander.Kolbasov@Sun.COM if (req[i].kr_data == NULL) 2234*11389SAlexander.Kolbasov@Sun.COM break; 2235*11389SAlexander.Kolbasov@Sun.COM 2236*11389SAlexander.Kolbasov@Sun.COM ret = update_func(req[i].kr_ptr, *req[i].kr_data); 2237*11389SAlexander.Kolbasov@Sun.COM if (ret < 0) 2238*11389SAlexander.Kolbasov@Sun.COM retval = ret; 2239*11389SAlexander.Kolbasov@Sun.COM } 2240*11389SAlexander.Kolbasov@Sun.COM 2241*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 2242*11389SAlexander.Kolbasov@Sun.COM 2243*11389SAlexander.Kolbasov@Sun.COM return (retval); 2244*11389SAlexander.Kolbasov@Sun.COM } 2245*11389SAlexander.Kolbasov@Sun.COM 2246*11389SAlexander.Kolbasov@Sun.COM /* 2247*11389SAlexander.Kolbasov@Sun.COM * Initialize list of counter event requests 2248*11389SAlexander.Kolbasov@Sun.COM */ 2249*11389SAlexander.Kolbasov@Sun.COM kcpc_request_list_t * 2250*11389SAlexander.Kolbasov@Sun.COM kcpc_reqs_init(int nreqs, int kmem_flags) 2251*11389SAlexander.Kolbasov@Sun.COM { 2252*11389SAlexander.Kolbasov@Sun.COM kcpc_request_list_t *req_list; 2253*11389SAlexander.Kolbasov@Sun.COM kcpc_request_t *reqs; 2254*11389SAlexander.Kolbasov@Sun.COM 2255*11389SAlexander.Kolbasov@Sun.COM if (nreqs < 1) 2256*11389SAlexander.Kolbasov@Sun.COM return (NULL); 2257*11389SAlexander.Kolbasov@Sun.COM 2258*11389SAlexander.Kolbasov@Sun.COM req_list = kmem_zalloc(sizeof (kcpc_request_list_t), kmem_flags); 2259*11389SAlexander.Kolbasov@Sun.COM if (req_list == NULL) 2260*11389SAlexander.Kolbasov@Sun.COM return (NULL); 2261*11389SAlexander.Kolbasov@Sun.COM 2262*11389SAlexander.Kolbasov@Sun.COM reqs = kmem_zalloc(nreqs * sizeof (kcpc_request_t), kmem_flags); 2263*11389SAlexander.Kolbasov@Sun.COM if (reqs == NULL) { 2264*11389SAlexander.Kolbasov@Sun.COM kmem_free(req_list, sizeof (kcpc_request_list_t)); 2265*11389SAlexander.Kolbasov@Sun.COM return (NULL); 2266*11389SAlexander.Kolbasov@Sun.COM } 2267*11389SAlexander.Kolbasov@Sun.COM 2268*11389SAlexander.Kolbasov@Sun.COM req_list->krl_list = reqs; 2269*11389SAlexander.Kolbasov@Sun.COM req_list->krl_cnt = 0; 2270*11389SAlexander.Kolbasov@Sun.COM req_list->krl_max = nreqs; 2271*11389SAlexander.Kolbasov@Sun.COM return (req_list); 2272*11389SAlexander.Kolbasov@Sun.COM } 2273*11389SAlexander.Kolbasov@Sun.COM 2274*11389SAlexander.Kolbasov@Sun.COM 2275*11389SAlexander.Kolbasov@Sun.COM /* 2276*11389SAlexander.Kolbasov@Sun.COM * Add counter event request to given list of counter event requests 2277*11389SAlexander.Kolbasov@Sun.COM */ 2278*11389SAlexander.Kolbasov@Sun.COM int 2279*11389SAlexander.Kolbasov@Sun.COM kcpc_reqs_add(kcpc_request_list_t *req_list, char *event, uint64_t preset, 2280*11389SAlexander.Kolbasov@Sun.COM uint_t flags, uint_t nattrs, kcpc_attr_t *attr, void *ptr, int kmem_flags) 2281*11389SAlexander.Kolbasov@Sun.COM { 2282*11389SAlexander.Kolbasov@Sun.COM kcpc_request_t *req; 2283*11389SAlexander.Kolbasov@Sun.COM 2284*11389SAlexander.Kolbasov@Sun.COM ASSERT(req_list->krl_max != 0); 2285*11389SAlexander.Kolbasov@Sun.COM if (req_list == NULL || req_list->krl_list == NULL) 2286*11389SAlexander.Kolbasov@Sun.COM return (-1); 2287*11389SAlexander.Kolbasov@Sun.COM 2288*11389SAlexander.Kolbasov@Sun.COM /* 2289*11389SAlexander.Kolbasov@Sun.COM * Allocate more space (if needed) 2290*11389SAlexander.Kolbasov@Sun.COM */ 2291*11389SAlexander.Kolbasov@Sun.COM if (req_list->krl_cnt > req_list->krl_max) { 2292*11389SAlexander.Kolbasov@Sun.COM kcpc_request_t *new; 2293*11389SAlexander.Kolbasov@Sun.COM kcpc_request_t *old; 2294*11389SAlexander.Kolbasov@Sun.COM 2295*11389SAlexander.Kolbasov@Sun.COM old = req_list->krl_list; 2296*11389SAlexander.Kolbasov@Sun.COM new = kmem_zalloc((req_list->krl_max + 2297*11389SAlexander.Kolbasov@Sun.COM cpc_ncounters) * sizeof (kcpc_request_t), kmem_flags); 2298*11389SAlexander.Kolbasov@Sun.COM if (new == NULL) 2299*11389SAlexander.Kolbasov@Sun.COM return (-2); 2300*11389SAlexander.Kolbasov@Sun.COM 2301*11389SAlexander.Kolbasov@Sun.COM req_list->krl_list = new; 2302*11389SAlexander.Kolbasov@Sun.COM bcopy(old, req_list->krl_list, 2303*11389SAlexander.Kolbasov@Sun.COM req_list->krl_cnt * sizeof (kcpc_request_t)); 2304*11389SAlexander.Kolbasov@Sun.COM kmem_free(old, req_list->krl_max * sizeof (kcpc_request_t)); 2305*11389SAlexander.Kolbasov@Sun.COM req_list->krl_cnt = 0; 2306*11389SAlexander.Kolbasov@Sun.COM req_list->krl_max += cpc_ncounters; 2307*11389SAlexander.Kolbasov@Sun.COM } 2308*11389SAlexander.Kolbasov@Sun.COM 2309*11389SAlexander.Kolbasov@Sun.COM /* 2310*11389SAlexander.Kolbasov@Sun.COM * Fill in request as much as possible now, but some fields will need 2311*11389SAlexander.Kolbasov@Sun.COM * to be set when request is assigned to a set. 2312*11389SAlexander.Kolbasov@Sun.COM */ 2313*11389SAlexander.Kolbasov@Sun.COM req = &req_list->krl_list[req_list->krl_cnt]; 2314*11389SAlexander.Kolbasov@Sun.COM req->kr_config = NULL; 2315*11389SAlexander.Kolbasov@Sun.COM req->kr_picnum = -1; /* have CPC pick this */ 2316*11389SAlexander.Kolbasov@Sun.COM req->kr_index = -1; /* set when assigning request to set */ 2317*11389SAlexander.Kolbasov@Sun.COM req->kr_data = NULL; /* set when configuring request */ 2318*11389SAlexander.Kolbasov@Sun.COM (void) strcpy(req->kr_event, event); 2319*11389SAlexander.Kolbasov@Sun.COM req->kr_preset = preset; 2320*11389SAlexander.Kolbasov@Sun.COM req->kr_flags = flags; 2321*11389SAlexander.Kolbasov@Sun.COM req->kr_nattrs = nattrs; 2322*11389SAlexander.Kolbasov@Sun.COM req->kr_attr = attr; 2323*11389SAlexander.Kolbasov@Sun.COM /* 2324*11389SAlexander.Kolbasov@Sun.COM * Keep pointer given by caller to give to update function when this 2325*11389SAlexander.Kolbasov@Sun.COM * counter event is sampled/read 2326*11389SAlexander.Kolbasov@Sun.COM */ 2327*11389SAlexander.Kolbasov@Sun.COM req->kr_ptr = ptr; 2328*11389SAlexander.Kolbasov@Sun.COM 2329*11389SAlexander.Kolbasov@Sun.COM req_list->krl_cnt++; 2330*11389SAlexander.Kolbasov@Sun.COM 2331*11389SAlexander.Kolbasov@Sun.COM return (0); 2332*11389SAlexander.Kolbasov@Sun.COM } 2333*11389SAlexander.Kolbasov@Sun.COM 2334*11389SAlexander.Kolbasov@Sun.COM /* 2335*11389SAlexander.Kolbasov@Sun.COM * Reset list of CPC event requests so its space can be used for another set 2336*11389SAlexander.Kolbasov@Sun.COM * of requests 2337*11389SAlexander.Kolbasov@Sun.COM */ 2338*11389SAlexander.Kolbasov@Sun.COM int 2339*11389SAlexander.Kolbasov@Sun.COM kcpc_reqs_reset(kcpc_request_list_t *req_list) 2340*11389SAlexander.Kolbasov@Sun.COM { 2341*11389SAlexander.Kolbasov@Sun.COM /* 2342*11389SAlexander.Kolbasov@Sun.COM * Return when pointer to request list structure or request is NULL or 2343*11389SAlexander.Kolbasov@Sun.COM * when max requests is less than or equal to 0 2344*11389SAlexander.Kolbasov@Sun.COM */ 2345*11389SAlexander.Kolbasov@Sun.COM if (req_list == NULL || req_list->krl_list == NULL || 2346*11389SAlexander.Kolbasov@Sun.COM req_list->krl_max <= 0) 2347*11389SAlexander.Kolbasov@Sun.COM return (-1); 2348*11389SAlexander.Kolbasov@Sun.COM 2349*11389SAlexander.Kolbasov@Sun.COM /* 2350*11389SAlexander.Kolbasov@Sun.COM * Zero out requests and number of requests used 2351*11389SAlexander.Kolbasov@Sun.COM */ 2352*11389SAlexander.Kolbasov@Sun.COM bzero(req_list->krl_list, req_list->krl_max * sizeof (kcpc_request_t)); 2353*11389SAlexander.Kolbasov@Sun.COM req_list->krl_cnt = 0; 2354*11389SAlexander.Kolbasov@Sun.COM return (0); 2355*11389SAlexander.Kolbasov@Sun.COM } 2356*11389SAlexander.Kolbasov@Sun.COM 2357*11389SAlexander.Kolbasov@Sun.COM /* 2358*11389SAlexander.Kolbasov@Sun.COM * Free given list of counter event requests 2359*11389SAlexander.Kolbasov@Sun.COM */ 2360*11389SAlexander.Kolbasov@Sun.COM int 2361*11389SAlexander.Kolbasov@Sun.COM kcpc_reqs_fini(kcpc_request_list_t *req_list) 2362*11389SAlexander.Kolbasov@Sun.COM { 2363*11389SAlexander.Kolbasov@Sun.COM kmem_free(req_list->krl_list, 2364*11389SAlexander.Kolbasov@Sun.COM req_list->krl_max * sizeof (kcpc_request_t)); 2365*11389SAlexander.Kolbasov@Sun.COM kmem_free(req_list, sizeof (kcpc_request_list_t)); 2366*11389SAlexander.Kolbasov@Sun.COM return (0); 2367*11389SAlexander.Kolbasov@Sun.COM } 2368*11389SAlexander.Kolbasov@Sun.COM 2369*11389SAlexander.Kolbasov@Sun.COM /* 2370*11389SAlexander.Kolbasov@Sun.COM * Create set of given counter event requests 2371*11389SAlexander.Kolbasov@Sun.COM */ 2372*11389SAlexander.Kolbasov@Sun.COM static kcpc_set_t * 2373*11389SAlexander.Kolbasov@Sun.COM kcpc_set_create(kcpc_request_t *reqs, int nreqs, int set_flags, int kmem_flags) 2374*11389SAlexander.Kolbasov@Sun.COM { 2375*11389SAlexander.Kolbasov@Sun.COM int i; 2376*11389SAlexander.Kolbasov@Sun.COM kcpc_set_t *set; 2377*11389SAlexander.Kolbasov@Sun.COM 2378*11389SAlexander.Kolbasov@Sun.COM /* 2379*11389SAlexander.Kolbasov@Sun.COM * Allocate set and assign number of requests in set and flags 2380*11389SAlexander.Kolbasov@Sun.COM */ 2381*11389SAlexander.Kolbasov@Sun.COM set = kmem_zalloc(sizeof (kcpc_set_t), kmem_flags); 2382*11389SAlexander.Kolbasov@Sun.COM if (set == NULL) 2383*11389SAlexander.Kolbasov@Sun.COM return (NULL); 2384*11389SAlexander.Kolbasov@Sun.COM 2385*11389SAlexander.Kolbasov@Sun.COM if (nreqs < cpc_ncounters) 2386*11389SAlexander.Kolbasov@Sun.COM set->ks_nreqs = nreqs; 2387*11389SAlexander.Kolbasov@Sun.COM else 2388*11389SAlexander.Kolbasov@Sun.COM set->ks_nreqs = cpc_ncounters; 2389*11389SAlexander.Kolbasov@Sun.COM 2390*11389SAlexander.Kolbasov@Sun.COM set->ks_flags = set_flags; 2391*11389SAlexander.Kolbasov@Sun.COM 2392*11389SAlexander.Kolbasov@Sun.COM /* 2393*11389SAlexander.Kolbasov@Sun.COM * Allocate requests needed, copy requests into set, and set index into 2394*11389SAlexander.Kolbasov@Sun.COM * data for each request (which may change when we assign requested 2395*11389SAlexander.Kolbasov@Sun.COM * counter events to counters) 2396*11389SAlexander.Kolbasov@Sun.COM */ 2397*11389SAlexander.Kolbasov@Sun.COM set->ks_req = (kcpc_request_t *)kmem_zalloc(sizeof (kcpc_request_t) * 2398*11389SAlexander.Kolbasov@Sun.COM set->ks_nreqs, kmem_flags); 2399*11389SAlexander.Kolbasov@Sun.COM if (set->ks_req == NULL) { 2400*11389SAlexander.Kolbasov@Sun.COM kmem_free(set, sizeof (kcpc_set_t)); 2401*11389SAlexander.Kolbasov@Sun.COM return (NULL); 2402*11389SAlexander.Kolbasov@Sun.COM } 2403*11389SAlexander.Kolbasov@Sun.COM 2404*11389SAlexander.Kolbasov@Sun.COM bcopy(reqs, set->ks_req, sizeof (kcpc_request_t) * set->ks_nreqs); 2405*11389SAlexander.Kolbasov@Sun.COM 2406*11389SAlexander.Kolbasov@Sun.COM for (i = 0; i < set->ks_nreqs; i++) 2407*11389SAlexander.Kolbasov@Sun.COM set->ks_req[i].kr_index = i; 2408*11389SAlexander.Kolbasov@Sun.COM 2409*11389SAlexander.Kolbasov@Sun.COM return (set); 2410*11389SAlexander.Kolbasov@Sun.COM } 2411*11389SAlexander.Kolbasov@Sun.COM 2412*11389SAlexander.Kolbasov@Sun.COM 2413*11389SAlexander.Kolbasov@Sun.COM /* 2414*11389SAlexander.Kolbasov@Sun.COM * Stop counters on current CPU. 2415*11389SAlexander.Kolbasov@Sun.COM * 2416*11389SAlexander.Kolbasov@Sun.COM * If preserve_context is true, the caller is interested in the CPU's CPC 2417*11389SAlexander.Kolbasov@Sun.COM * context and wants it to be preserved. 2418*11389SAlexander.Kolbasov@Sun.COM * 2419*11389SAlexander.Kolbasov@Sun.COM * If preserve_context is false, the caller does not need the CPU's CPC context 2420*11389SAlexander.Kolbasov@Sun.COM * to be preserved, so it is set to NULL. 2421*11389SAlexander.Kolbasov@Sun.COM */ 2422*11389SAlexander.Kolbasov@Sun.COM static void 2423*11389SAlexander.Kolbasov@Sun.COM kcpc_cpustop_func(boolean_t preserve_context) 2424*11389SAlexander.Kolbasov@Sun.COM { 2425*11389SAlexander.Kolbasov@Sun.COM kpreempt_disable(); 2426*11389SAlexander.Kolbasov@Sun.COM 2427*11389SAlexander.Kolbasov@Sun.COM /* 2428*11389SAlexander.Kolbasov@Sun.COM * Someone already stopped this context before us, so there is nothing 2429*11389SAlexander.Kolbasov@Sun.COM * to do. 2430*11389SAlexander.Kolbasov@Sun.COM */ 2431*11389SAlexander.Kolbasov@Sun.COM if (CPU->cpu_cpc_ctx == NULL) { 2432*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 2433*11389SAlexander.Kolbasov@Sun.COM return; 2434*11389SAlexander.Kolbasov@Sun.COM } 2435*11389SAlexander.Kolbasov@Sun.COM 2436*11389SAlexander.Kolbasov@Sun.COM kcpc_unprogram(CPU->cpu_cpc_ctx, B_TRUE); 2437*11389SAlexander.Kolbasov@Sun.COM /* 2438*11389SAlexander.Kolbasov@Sun.COM * If CU does not use counters, then clear the CPU's CPC context 2439*11389SAlexander.Kolbasov@Sun.COM * If the caller requested to preserve context it should disable CU 2440*11389SAlexander.Kolbasov@Sun.COM * first, so there should be no CU context now. 2441*11389SAlexander.Kolbasov@Sun.COM */ 2442*11389SAlexander.Kolbasov@Sun.COM ASSERT(!preserve_context || !CU_CPC_ON(CPU)); 2443*11389SAlexander.Kolbasov@Sun.COM if (!preserve_context && CPU->cpu_cpc_ctx != NULL && !CU_CPC_ON(CPU)) 2444*11389SAlexander.Kolbasov@Sun.COM CPU->cpu_cpc_ctx = NULL; 2445*11389SAlexander.Kolbasov@Sun.COM 2446*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 2447*11389SAlexander.Kolbasov@Sun.COM } 2448*11389SAlexander.Kolbasov@Sun.COM 2449*11389SAlexander.Kolbasov@Sun.COM /* 2450*11389SAlexander.Kolbasov@Sun.COM * Stop counters on given CPU and set its CPC context to NULL unless 2451*11389SAlexander.Kolbasov@Sun.COM * preserve_context is true. 2452*11389SAlexander.Kolbasov@Sun.COM */ 2453*11389SAlexander.Kolbasov@Sun.COM void 2454*11389SAlexander.Kolbasov@Sun.COM kcpc_cpu_stop(cpu_t *cp, boolean_t preserve_context) 2455*11389SAlexander.Kolbasov@Sun.COM { 2456*11389SAlexander.Kolbasov@Sun.COM cpu_call(cp, (cpu_call_func_t)kcpc_cpustop_func, 2457*11389SAlexander.Kolbasov@Sun.COM preserve_context, 0); 2458*11389SAlexander.Kolbasov@Sun.COM } 2459*11389SAlexander.Kolbasov@Sun.COM 2460*11389SAlexander.Kolbasov@Sun.COM /* 2461*11389SAlexander.Kolbasov@Sun.COM * Program the context on the current CPU 2462*11389SAlexander.Kolbasov@Sun.COM */ 2463*11389SAlexander.Kolbasov@Sun.COM static void 2464*11389SAlexander.Kolbasov@Sun.COM kcpc_remoteprogram_func(kcpc_ctx_t *ctx, uintptr_t arg) 2465*11389SAlexander.Kolbasov@Sun.COM { 2466*11389SAlexander.Kolbasov@Sun.COM boolean_t for_thread = (boolean_t)arg; 2467*11389SAlexander.Kolbasov@Sun.COM 2468*11389SAlexander.Kolbasov@Sun.COM ASSERT(ctx != NULL); 2469*11389SAlexander.Kolbasov@Sun.COM 2470*11389SAlexander.Kolbasov@Sun.COM kpreempt_disable(); 2471*11389SAlexander.Kolbasov@Sun.COM kcpc_program(ctx, for_thread, B_TRUE); 2472*11389SAlexander.Kolbasov@Sun.COM kpreempt_enable(); 2473*11389SAlexander.Kolbasov@Sun.COM } 2474*11389SAlexander.Kolbasov@Sun.COM 2475*11389SAlexander.Kolbasov@Sun.COM /* 2476*11389SAlexander.Kolbasov@Sun.COM * Program counters on given CPU 2477*11389SAlexander.Kolbasov@Sun.COM */ 2478*11389SAlexander.Kolbasov@Sun.COM void 2479*11389SAlexander.Kolbasov@Sun.COM kcpc_cpu_program(cpu_t *cp, kcpc_ctx_t *ctx) 2480*11389SAlexander.Kolbasov@Sun.COM { 2481*11389SAlexander.Kolbasov@Sun.COM cpu_call(cp, (cpu_call_func_t)kcpc_remoteprogram_func, (uintptr_t)ctx, 2482*11389SAlexander.Kolbasov@Sun.COM (uintptr_t)B_FALSE); 2483*11389SAlexander.Kolbasov@Sun.COM } 2484*11389SAlexander.Kolbasov@Sun.COM 24858803SJonathan.Haslam@Sun.COM char * 24868803SJonathan.Haslam@Sun.COM kcpc_list_attrs(void) 24878803SJonathan.Haslam@Sun.COM { 24888803SJonathan.Haslam@Sun.COM ASSERT(pcbe_ops != NULL); 24898803SJonathan.Haslam@Sun.COM 24908803SJonathan.Haslam@Sun.COM return (pcbe_ops->pcbe_list_attrs()); 24918803SJonathan.Haslam@Sun.COM } 24928803SJonathan.Haslam@Sun.COM 24938803SJonathan.Haslam@Sun.COM char * 24948803SJonathan.Haslam@Sun.COM kcpc_list_events(uint_t pic) 24958803SJonathan.Haslam@Sun.COM { 24968803SJonathan.Haslam@Sun.COM ASSERT(pcbe_ops != NULL); 24978803SJonathan.Haslam@Sun.COM 24988803SJonathan.Haslam@Sun.COM return (pcbe_ops->pcbe_list_events(pic)); 24998803SJonathan.Haslam@Sun.COM } 25008803SJonathan.Haslam@Sun.COM 25018803SJonathan.Haslam@Sun.COM uint_t 25028803SJonathan.Haslam@Sun.COM kcpc_pcbe_capabilities(void) 25038803SJonathan.Haslam@Sun.COM { 25048803SJonathan.Haslam@Sun.COM ASSERT(pcbe_ops != NULL); 25058803SJonathan.Haslam@Sun.COM 25068803SJonathan.Haslam@Sun.COM return (pcbe_ops->pcbe_caps); 25078803SJonathan.Haslam@Sun.COM } 25088803SJonathan.Haslam@Sun.COM 25098803SJonathan.Haslam@Sun.COM int 25108803SJonathan.Haslam@Sun.COM kcpc_pcbe_loaded(void) 25118803SJonathan.Haslam@Sun.COM { 25128803SJonathan.Haslam@Sun.COM return (pcbe_ops == NULL ? -1 : 0); 25138803SJonathan.Haslam@Sun.COM } 2514