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 /*
23*13070SEthindra.Ramamurthy@Sun.COM * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <sys/param.h>
270Sstevel@tonic-gate #include <sys/thread.h>
280Sstevel@tonic-gate #include <sys/cpuvar.h>
290Sstevel@tonic-gate #include <sys/inttypes.h>
300Sstevel@tonic-gate #include <sys/cmn_err.h>
310Sstevel@tonic-gate #include <sys/time.h>
326275Strevtom #include <sys/ksynch.h>
330Sstevel@tonic-gate #include <sys/systm.h>
340Sstevel@tonic-gate #include <sys/kcpc.h>
350Sstevel@tonic-gate #include <sys/cpc_impl.h>
360Sstevel@tonic-gate #include <sys/cpc_pcbe.h>
370Sstevel@tonic-gate #include <sys/atomic.h>
380Sstevel@tonic-gate #include <sys/sunddi.h>
390Sstevel@tonic-gate #include <sys/modctl.h>
400Sstevel@tonic-gate #include <sys/sdt.h>
4111389SAlexander.Kolbasov@Sun.COM #include <sys/archsystm.h>
4211389SAlexander.Kolbasov@Sun.COM #include <sys/promif.h>
4311389SAlexander.Kolbasov@Sun.COM #include <sys/x_call.h>
4411389SAlexander.Kolbasov@Sun.COM #include <sys/cap_util.h>
450Sstevel@tonic-gate #if defined(__x86)
460Sstevel@tonic-gate #include <asm/clock.h>
4711389SAlexander.Kolbasov@Sun.COM #include <sys/xc_levels.h>
480Sstevel@tonic-gate #endif
490Sstevel@tonic-gate
5011389SAlexander.Kolbasov@Sun.COM static kmutex_t kcpc_ctx_llock[CPC_HASH_BUCKETS]; /* protects ctx_list */
5111389SAlexander.Kolbasov@Sun.COM static kcpc_ctx_t *kcpc_ctx_list[CPC_HASH_BUCKETS]; /* head of list */
520Sstevel@tonic-gate
530Sstevel@tonic-gate
540Sstevel@tonic-gate krwlock_t kcpc_cpuctx_lock; /* lock for 'kcpc_cpuctx' below */
550Sstevel@tonic-gate int kcpc_cpuctx; /* number of cpu-specific contexts */
560Sstevel@tonic-gate
570Sstevel@tonic-gate int kcpc_counts_include_idle = 1; /* Project Private /etc/system variable */
580Sstevel@tonic-gate
590Sstevel@tonic-gate /*
600Sstevel@tonic-gate * These are set when a PCBE module is loaded.
610Sstevel@tonic-gate */
620Sstevel@tonic-gate uint_t cpc_ncounters = 0;
630Sstevel@tonic-gate pcbe_ops_t *pcbe_ops = NULL;
640Sstevel@tonic-gate
650Sstevel@tonic-gate /*
660Sstevel@tonic-gate * Statistics on (mis)behavior
670Sstevel@tonic-gate */
680Sstevel@tonic-gate static uint32_t kcpc_intrctx_count; /* # overflows in an interrupt handler */
690Sstevel@tonic-gate static uint32_t kcpc_nullctx_count; /* # overflows in a thread with no ctx */
700Sstevel@tonic-gate
710Sstevel@tonic-gate /*
728803SJonathan.Haslam@Sun.COM * By setting 'kcpc_nullctx_panic' to 1, any overflow interrupts in a thread
738803SJonathan.Haslam@Sun.COM * with no valid context will result in a panic.
740Sstevel@tonic-gate */
750Sstevel@tonic-gate static int kcpc_nullctx_panic = 0;
760Sstevel@tonic-gate
770Sstevel@tonic-gate static void kcpc_lwp_create(kthread_t *t, kthread_t *ct);
780Sstevel@tonic-gate static void kcpc_restore(kcpc_ctx_t *ctx);
790Sstevel@tonic-gate static void kcpc_save(kcpc_ctx_t *ctx);
800Sstevel@tonic-gate static void kcpc_ctx_clone(kcpc_ctx_t *ctx, kcpc_ctx_t *cctx);
810Sstevel@tonic-gate static int kcpc_tryassign(kcpc_set_t *set, int starting_req, int *scratch);
820Sstevel@tonic-gate static kcpc_set_t *kcpc_dup_set(kcpc_set_t *set);
8311389SAlexander.Kolbasov@Sun.COM static kcpc_set_t *kcpc_set_create(kcpc_request_t *reqs, int nreqs,
8411389SAlexander.Kolbasov@Sun.COM int set_flags, int kmem_flags);
8511389SAlexander.Kolbasov@Sun.COM
8611389SAlexander.Kolbasov@Sun.COM /*
8711389SAlexander.Kolbasov@Sun.COM * Macros to manipulate context flags. All flag updates should use one of these
8811389SAlexander.Kolbasov@Sun.COM * two macros
8911389SAlexander.Kolbasov@Sun.COM *
9011389SAlexander.Kolbasov@Sun.COM * Flags should be always be updated atomically since some of the updates are
9111389SAlexander.Kolbasov@Sun.COM * not protected by locks.
9211389SAlexander.Kolbasov@Sun.COM */
9311389SAlexander.Kolbasov@Sun.COM #define KCPC_CTX_FLAG_SET(ctx, flag) atomic_or_uint(&(ctx)->kc_flags, (flag))
9411389SAlexander.Kolbasov@Sun.COM #define KCPC_CTX_FLAG_CLR(ctx, flag) atomic_and_uint(&(ctx)->kc_flags, ~(flag))
9511389SAlexander.Kolbasov@Sun.COM
9611389SAlexander.Kolbasov@Sun.COM /*
9711389SAlexander.Kolbasov@Sun.COM * The IS_HIPIL() macro verifies that the code is executed either from a
9811389SAlexander.Kolbasov@Sun.COM * cross-call or from high-PIL interrupt
9911389SAlexander.Kolbasov@Sun.COM */
10011389SAlexander.Kolbasov@Sun.COM #ifdef DEBUG
10111389SAlexander.Kolbasov@Sun.COM #define IS_HIPIL() (getpil() >= XCALL_PIL)
10211389SAlexander.Kolbasov@Sun.COM #else
10311389SAlexander.Kolbasov@Sun.COM #define IS_HIPIL()
10411389SAlexander.Kolbasov@Sun.COM #endif /* DEBUG */
10511389SAlexander.Kolbasov@Sun.COM
10611389SAlexander.Kolbasov@Sun.COM
10711389SAlexander.Kolbasov@Sun.COM extern int kcpc_hw_load_pcbe(void);
10811389SAlexander.Kolbasov@Sun.COM
10911389SAlexander.Kolbasov@Sun.COM /*
11011389SAlexander.Kolbasov@Sun.COM * Return value from kcpc_hw_load_pcbe()
11111389SAlexander.Kolbasov@Sun.COM */
11211389SAlexander.Kolbasov@Sun.COM static int kcpc_pcbe_error = 0;
11311389SAlexander.Kolbasov@Sun.COM
11411389SAlexander.Kolbasov@Sun.COM /*
11511389SAlexander.Kolbasov@Sun.COM * Perform one-time initialization of kcpc framework.
11611389SAlexander.Kolbasov@Sun.COM * This function performs the initialization only the first time it is called.
11711389SAlexander.Kolbasov@Sun.COM * It is safe to call it multiple times.
11811389SAlexander.Kolbasov@Sun.COM */
11911389SAlexander.Kolbasov@Sun.COM int
kcpc_init(void)12011389SAlexander.Kolbasov@Sun.COM kcpc_init(void)
12111389SAlexander.Kolbasov@Sun.COM {
12211389SAlexander.Kolbasov@Sun.COM long hash;
12311389SAlexander.Kolbasov@Sun.COM static uint32_t kcpc_initialized = 0;
12411389SAlexander.Kolbasov@Sun.COM
12511389SAlexander.Kolbasov@Sun.COM /*
12611389SAlexander.Kolbasov@Sun.COM * We already tried loading platform pcbe module and failed
12711389SAlexander.Kolbasov@Sun.COM */
12811389SAlexander.Kolbasov@Sun.COM if (kcpc_pcbe_error != 0)
12911389SAlexander.Kolbasov@Sun.COM return (-1);
13011389SAlexander.Kolbasov@Sun.COM
13111389SAlexander.Kolbasov@Sun.COM /*
13211389SAlexander.Kolbasov@Sun.COM * The kcpc framework should be initialized at most once
13311389SAlexander.Kolbasov@Sun.COM */
13411389SAlexander.Kolbasov@Sun.COM if (atomic_cas_32(&kcpc_initialized, 0, 1) != 0)
13511389SAlexander.Kolbasov@Sun.COM return (0);
13611389SAlexander.Kolbasov@Sun.COM
13711389SAlexander.Kolbasov@Sun.COM rw_init(&kcpc_cpuctx_lock, NULL, RW_DEFAULT, NULL);
13811389SAlexander.Kolbasov@Sun.COM for (hash = 0; hash < CPC_HASH_BUCKETS; hash++)
13911389SAlexander.Kolbasov@Sun.COM mutex_init(&kcpc_ctx_llock[hash],
14011389SAlexander.Kolbasov@Sun.COM NULL, MUTEX_DRIVER, (void *)(uintptr_t)15);
14111389SAlexander.Kolbasov@Sun.COM
14211389SAlexander.Kolbasov@Sun.COM /*
14311389SAlexander.Kolbasov@Sun.COM * Load platform-specific pcbe module
14411389SAlexander.Kolbasov@Sun.COM */
14511389SAlexander.Kolbasov@Sun.COM kcpc_pcbe_error = kcpc_hw_load_pcbe();
14611389SAlexander.Kolbasov@Sun.COM
14711389SAlexander.Kolbasov@Sun.COM return (kcpc_pcbe_error == 0 ? 0 : -1);
14811389SAlexander.Kolbasov@Sun.COM }
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate void
kcpc_register_pcbe(pcbe_ops_t * ops)1510Sstevel@tonic-gate kcpc_register_pcbe(pcbe_ops_t *ops)
1520Sstevel@tonic-gate {
1530Sstevel@tonic-gate pcbe_ops = ops;
1540Sstevel@tonic-gate cpc_ncounters = pcbe_ops->pcbe_ncounters();
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate
1578803SJonathan.Haslam@Sun.COM void
kcpc_register_dcpc(void (* func)(uint64_t))1588803SJonathan.Haslam@Sun.COM kcpc_register_dcpc(void (*func)(uint64_t))
1598803SJonathan.Haslam@Sun.COM {
1608803SJonathan.Haslam@Sun.COM dtrace_cpc_fire = func;
1618803SJonathan.Haslam@Sun.COM }
1628803SJonathan.Haslam@Sun.COM
1638803SJonathan.Haslam@Sun.COM void
kcpc_unregister_dcpc(void)1648803SJonathan.Haslam@Sun.COM kcpc_unregister_dcpc(void)
1658803SJonathan.Haslam@Sun.COM {
1668803SJonathan.Haslam@Sun.COM dtrace_cpc_fire = NULL;
1678803SJonathan.Haslam@Sun.COM }
1688803SJonathan.Haslam@Sun.COM
1690Sstevel@tonic-gate int
kcpc_bind_cpu(kcpc_set_t * set,processorid_t cpuid,int * subcode)1700Sstevel@tonic-gate kcpc_bind_cpu(kcpc_set_t *set, processorid_t cpuid, int *subcode)
1710Sstevel@tonic-gate {
1720Sstevel@tonic-gate cpu_t *cp;
1730Sstevel@tonic-gate kcpc_ctx_t *ctx;
1740Sstevel@tonic-gate int error;
17511389SAlexander.Kolbasov@Sun.COM int save_spl;
1760Sstevel@tonic-gate
17711389SAlexander.Kolbasov@Sun.COM ctx = kcpc_ctx_alloc(KM_SLEEP);
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate if (kcpc_assign_reqs(set, ctx) != 0) {
1800Sstevel@tonic-gate kcpc_ctx_free(ctx);
1810Sstevel@tonic-gate *subcode = CPC_RESOURCE_UNAVAIL;
1820Sstevel@tonic-gate return (EINVAL);
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate ctx->kc_cpuid = cpuid;
1860Sstevel@tonic-gate ctx->kc_thread = curthread;
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate set->ks_data = kmem_zalloc(set->ks_nreqs * sizeof (uint64_t), KM_SLEEP);
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate if ((error = kcpc_configure_reqs(ctx, set, subcode)) != 0) {
1910Sstevel@tonic-gate kmem_free(set->ks_data, set->ks_nreqs * sizeof (uint64_t));
1920Sstevel@tonic-gate kcpc_ctx_free(ctx);
1930Sstevel@tonic-gate return (error);
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate set->ks_ctx = ctx;
1970Sstevel@tonic-gate ctx->kc_set = set;
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate /*
2000Sstevel@tonic-gate * We must hold cpu_lock to prevent DR, offlining, or unbinding while
2010Sstevel@tonic-gate * we are manipulating the cpu_t and programming the hardware, else the
2020Sstevel@tonic-gate * the cpu_t could go away while we're looking at it.
2030Sstevel@tonic-gate */
2040Sstevel@tonic-gate mutex_enter(&cpu_lock);
2050Sstevel@tonic-gate cp = cpu_get(cpuid);
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate if (cp == NULL)
2080Sstevel@tonic-gate /*
2090Sstevel@tonic-gate * The CPU could have been DRd out while we were getting set up.
2100Sstevel@tonic-gate */
2110Sstevel@tonic-gate goto unbound;
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate mutex_enter(&cp->cpu_cpc_ctxlock);
21411389SAlexander.Kolbasov@Sun.COM kpreempt_disable();
21511389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall();
2160Sstevel@tonic-gate
21711389SAlexander.Kolbasov@Sun.COM /*
21811389SAlexander.Kolbasov@Sun.COM * Check to see whether counters for CPU already being used by someone
21911389SAlexander.Kolbasov@Sun.COM * other than kernel for capacity and utilization (since kernel will
22011389SAlexander.Kolbasov@Sun.COM * let go of counters for user in kcpc_program() below)
22111389SAlexander.Kolbasov@Sun.COM */
22211389SAlexander.Kolbasov@Sun.COM if (cp->cpu_cpc_ctx != NULL && !CU_CPC_ON(cp)) {
2230Sstevel@tonic-gate /*
2240Sstevel@tonic-gate * If this CPU already has a bound set, return an error.
2250Sstevel@tonic-gate */
22611389SAlexander.Kolbasov@Sun.COM splx(save_spl);
22711389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
2280Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock);
2290Sstevel@tonic-gate goto unbound;
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate if (curthread->t_bind_cpu != cpuid) {
23311389SAlexander.Kolbasov@Sun.COM splx(save_spl);
23411389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
2350Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock);
2360Sstevel@tonic-gate goto unbound;
2370Sstevel@tonic-gate }
2380Sstevel@tonic-gate
23911389SAlexander.Kolbasov@Sun.COM kcpc_program(ctx, B_FALSE, B_TRUE);
24011389SAlexander.Kolbasov@Sun.COM
24111389SAlexander.Kolbasov@Sun.COM splx(save_spl);
2420Sstevel@tonic-gate kpreempt_enable();
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock);
2450Sstevel@tonic-gate mutex_exit(&cpu_lock);
2460Sstevel@tonic-gate
2476275Strevtom mutex_enter(&set->ks_lock);
2486275Strevtom set->ks_state |= KCPC_SET_BOUND;
2496275Strevtom cv_signal(&set->ks_condv);
2506275Strevtom mutex_exit(&set->ks_lock);
2516275Strevtom
2520Sstevel@tonic-gate return (0);
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate unbound:
2550Sstevel@tonic-gate mutex_exit(&cpu_lock);
2560Sstevel@tonic-gate set->ks_ctx = NULL;
2570Sstevel@tonic-gate kmem_free(set->ks_data, set->ks_nreqs * sizeof (uint64_t));
2580Sstevel@tonic-gate kcpc_ctx_free(ctx);
2590Sstevel@tonic-gate return (EAGAIN);
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate int
kcpc_bind_thread(kcpc_set_t * set,kthread_t * t,int * subcode)2630Sstevel@tonic-gate kcpc_bind_thread(kcpc_set_t *set, kthread_t *t, int *subcode)
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate kcpc_ctx_t *ctx;
2660Sstevel@tonic-gate int error;
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate /*
2690Sstevel@tonic-gate * Only one set is allowed per context, so ensure there is no
2700Sstevel@tonic-gate * existing context.
2710Sstevel@tonic-gate */
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate if (t->t_cpc_ctx != NULL)
2740Sstevel@tonic-gate return (EEXIST);
2750Sstevel@tonic-gate
27611389SAlexander.Kolbasov@Sun.COM ctx = kcpc_ctx_alloc(KM_SLEEP);
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate /*
2790Sstevel@tonic-gate * The context must begin life frozen until it has been properly
2800Sstevel@tonic-gate * programmed onto the hardware. This prevents the context ops from
2810Sstevel@tonic-gate * worrying about it until we're ready.
2820Sstevel@tonic-gate */
28311389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_FREEZE);
2840Sstevel@tonic-gate ctx->kc_hrtime = gethrtime();
2850Sstevel@tonic-gate
2860Sstevel@tonic-gate if (kcpc_assign_reqs(set, ctx) != 0) {
2870Sstevel@tonic-gate kcpc_ctx_free(ctx);
2880Sstevel@tonic-gate *subcode = CPC_RESOURCE_UNAVAIL;
2890Sstevel@tonic-gate return (EINVAL);
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate ctx->kc_cpuid = -1;
2930Sstevel@tonic-gate if (set->ks_flags & CPC_BIND_LWP_INHERIT)
29411389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_LWPINHERIT);
2950Sstevel@tonic-gate ctx->kc_thread = t;
2960Sstevel@tonic-gate t->t_cpc_ctx = ctx;
2970Sstevel@tonic-gate /*
2980Sstevel@tonic-gate * Permit threads to look at their own hardware counters from userland.
2990Sstevel@tonic-gate */
30011389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_NONPRIV);
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate /*
3030Sstevel@tonic-gate * Create the data store for this set.
3040Sstevel@tonic-gate */
3050Sstevel@tonic-gate set->ks_data = kmem_alloc(set->ks_nreqs * sizeof (uint64_t), KM_SLEEP);
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate if ((error = kcpc_configure_reqs(ctx, set, subcode)) != 0) {
3080Sstevel@tonic-gate kmem_free(set->ks_data, set->ks_nreqs * sizeof (uint64_t));
3090Sstevel@tonic-gate kcpc_ctx_free(ctx);
3100Sstevel@tonic-gate t->t_cpc_ctx = NULL;
3110Sstevel@tonic-gate return (error);
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate set->ks_ctx = ctx;
3150Sstevel@tonic-gate ctx->kc_set = set;
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate /*
3180Sstevel@tonic-gate * Add a device context to the subject thread.
3190Sstevel@tonic-gate */
3200Sstevel@tonic-gate installctx(t, ctx, kcpc_save, kcpc_restore, NULL,
3210Sstevel@tonic-gate kcpc_lwp_create, NULL, kcpc_free);
3220Sstevel@tonic-gate
3230Sstevel@tonic-gate /*
3240Sstevel@tonic-gate * Ask the backend to program the hardware.
3250Sstevel@tonic-gate */
3260Sstevel@tonic-gate if (t == curthread) {
32711389SAlexander.Kolbasov@Sun.COM int save_spl;
32811389SAlexander.Kolbasov@Sun.COM
3290Sstevel@tonic-gate kpreempt_disable();
33011389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall();
33111389SAlexander.Kolbasov@Sun.COM kcpc_program(ctx, B_TRUE, B_TRUE);
33211389SAlexander.Kolbasov@Sun.COM splx(save_spl);
3330Sstevel@tonic-gate kpreempt_enable();
33411389SAlexander.Kolbasov@Sun.COM } else {
3350Sstevel@tonic-gate /*
3360Sstevel@tonic-gate * Since we are the agent LWP, we know the victim LWP is stopped
3370Sstevel@tonic-gate * until we're done here; no need to worry about preemption or
3380Sstevel@tonic-gate * migration here. We still use an atomic op to clear the flag
3390Sstevel@tonic-gate * to ensure the flags are always self-consistent; they can
3400Sstevel@tonic-gate * still be accessed from, for instance, another CPU doing a
3410Sstevel@tonic-gate * kcpc_invalidate_all().
3420Sstevel@tonic-gate */
34311389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_CLR(ctx, KCPC_CTX_FREEZE);
34411389SAlexander.Kolbasov@Sun.COM }
3450Sstevel@tonic-gate
3466275Strevtom mutex_enter(&set->ks_lock);
3476275Strevtom set->ks_state |= KCPC_SET_BOUND;
3486275Strevtom cv_signal(&set->ks_condv);
3496275Strevtom mutex_exit(&set->ks_lock);
3500Sstevel@tonic-gate
3510Sstevel@tonic-gate return (0);
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate /*
3550Sstevel@tonic-gate * Walk through each request in the set and ask the PCBE to configure a
3560Sstevel@tonic-gate * corresponding counter.
3570Sstevel@tonic-gate */
3588803SJonathan.Haslam@Sun.COM int
kcpc_configure_reqs(kcpc_ctx_t * ctx,kcpc_set_t * set,int * subcode)3590Sstevel@tonic-gate kcpc_configure_reqs(kcpc_ctx_t *ctx, kcpc_set_t *set, int *subcode)
3600Sstevel@tonic-gate {
3610Sstevel@tonic-gate int i;
3620Sstevel@tonic-gate int ret;
3630Sstevel@tonic-gate kcpc_request_t *rp;
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++) {
3660Sstevel@tonic-gate int n;
3670Sstevel@tonic-gate rp = &set->ks_req[i];
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate n = rp->kr_picnum;
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate ASSERT(n >= 0 && n < cpc_ncounters);
3720Sstevel@tonic-gate
3730Sstevel@tonic-gate ASSERT(ctx->kc_pics[n].kp_req == NULL);
3740Sstevel@tonic-gate
3750Sstevel@tonic-gate if (rp->kr_flags & CPC_OVF_NOTIFY_EMT) {
3760Sstevel@tonic-gate if ((pcbe_ops->pcbe_caps & CPC_CAP_OVERFLOW_INTERRUPT)
3770Sstevel@tonic-gate == 0) {
3780Sstevel@tonic-gate *subcode = -1;
3790Sstevel@tonic-gate return (ENOTSUP);
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate /*
3820Sstevel@tonic-gate * If any of the counters have requested overflow
3830Sstevel@tonic-gate * notification, we flag the context as being one that
3840Sstevel@tonic-gate * cares about overflow.
3850Sstevel@tonic-gate */
38611389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_SIGOVF);
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate
3890Sstevel@tonic-gate rp->kr_config = NULL;
3900Sstevel@tonic-gate if ((ret = pcbe_ops->pcbe_configure(n, rp->kr_event,
3910Sstevel@tonic-gate rp->kr_preset, rp->kr_flags, rp->kr_nattrs, rp->kr_attr,
3920Sstevel@tonic-gate &(rp->kr_config), (void *)ctx)) != 0) {
3930Sstevel@tonic-gate kcpc_free_configs(set);
3940Sstevel@tonic-gate *subcode = ret;
3953732Sae112802 switch (ret) {
3963732Sae112802 case CPC_ATTR_REQUIRES_PRIVILEGE:
3973732Sae112802 case CPC_HV_NO_ACCESS:
3980Sstevel@tonic-gate return (EACCES);
3993732Sae112802 default:
4003732Sae112802 return (EINVAL);
4013732Sae112802 }
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate
4040Sstevel@tonic-gate ctx->kc_pics[n].kp_req = rp;
4050Sstevel@tonic-gate rp->kr_picp = &ctx->kc_pics[n];
4060Sstevel@tonic-gate rp->kr_data = set->ks_data + rp->kr_index;
4070Sstevel@tonic-gate *rp->kr_data = rp->kr_preset;
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate return (0);
4110Sstevel@tonic-gate }
4120Sstevel@tonic-gate
4138803SJonathan.Haslam@Sun.COM void
kcpc_free_configs(kcpc_set_t * set)4140Sstevel@tonic-gate kcpc_free_configs(kcpc_set_t *set)
4150Sstevel@tonic-gate {
4160Sstevel@tonic-gate int i;
4170Sstevel@tonic-gate
4180Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++)
4190Sstevel@tonic-gate if (set->ks_req[i].kr_config != NULL)
4200Sstevel@tonic-gate pcbe_ops->pcbe_free(set->ks_req[i].kr_config);
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate
4230Sstevel@tonic-gate /*
4240Sstevel@tonic-gate * buf points to a user address and the data should be copied out to that
4250Sstevel@tonic-gate * address in the current process.
4260Sstevel@tonic-gate */
4270Sstevel@tonic-gate int
kcpc_sample(kcpc_set_t * set,uint64_t * buf,hrtime_t * hrtime,uint64_t * tick)4280Sstevel@tonic-gate kcpc_sample(kcpc_set_t *set, uint64_t *buf, hrtime_t *hrtime, uint64_t *tick)
4290Sstevel@tonic-gate {
4300Sstevel@tonic-gate kcpc_ctx_t *ctx = set->ks_ctx;
43111389SAlexander.Kolbasov@Sun.COM int save_spl;
4320Sstevel@tonic-gate
4336275Strevtom mutex_enter(&set->ks_lock);
4346275Strevtom if ((set->ks_state & KCPC_SET_BOUND) == 0) {
4356275Strevtom mutex_exit(&set->ks_lock);
4360Sstevel@tonic-gate return (EINVAL);
4376275Strevtom }
4386275Strevtom mutex_exit(&set->ks_lock);
4396275Strevtom
44011389SAlexander.Kolbasov@Sun.COM /*
44111389SAlexander.Kolbasov@Sun.COM * Kernel preemption must be disabled while reading the hardware regs,
44211389SAlexander.Kolbasov@Sun.COM * and if this is a CPU-bound context, while checking the CPU binding of
44311389SAlexander.Kolbasov@Sun.COM * the current thread.
44411389SAlexander.Kolbasov@Sun.COM */
44511389SAlexander.Kolbasov@Sun.COM kpreempt_disable();
44611389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall();
44711389SAlexander.Kolbasov@Sun.COM
44811389SAlexander.Kolbasov@Sun.COM if (ctx->kc_flags & KCPC_CTX_INVALID) {
44911389SAlexander.Kolbasov@Sun.COM splx(save_spl);
45011389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
4510Sstevel@tonic-gate return (EAGAIN);
45211389SAlexander.Kolbasov@Sun.COM }
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate if ((ctx->kc_flags & KCPC_CTX_FREEZE) == 0) {
4550Sstevel@tonic-gate if (ctx->kc_cpuid != -1) {
4560Sstevel@tonic-gate if (curthread->t_bind_cpu != ctx->kc_cpuid) {
45711389SAlexander.Kolbasov@Sun.COM splx(save_spl);
4580Sstevel@tonic-gate kpreempt_enable();
4590Sstevel@tonic-gate return (EAGAIN);
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate if (ctx->kc_thread == curthread) {
46411389SAlexander.Kolbasov@Sun.COM uint64_t curtick = KCPC_GET_TICK();
46511389SAlexander.Kolbasov@Sun.COM
46611389SAlexander.Kolbasov@Sun.COM ctx->kc_hrtime = gethrtime_waitfree();
4670Sstevel@tonic-gate pcbe_ops->pcbe_sample(ctx);
4680Sstevel@tonic-gate ctx->kc_vtick += curtick - ctx->kc_rawtick;
4690Sstevel@tonic-gate ctx->kc_rawtick = curtick;
4700Sstevel@tonic-gate }
4710Sstevel@tonic-gate
4723732Sae112802 /*
4733732Sae112802 * The config may have been invalidated by
4743732Sae112802 * the pcbe_sample op.
4753732Sae112802 */
47611389SAlexander.Kolbasov@Sun.COM if (ctx->kc_flags & KCPC_CTX_INVALID) {
47711389SAlexander.Kolbasov@Sun.COM splx(save_spl);
47811389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
4793732Sae112802 return (EAGAIN);
48011389SAlexander.Kolbasov@Sun.COM }
48111389SAlexander.Kolbasov@Sun.COM
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate
48411389SAlexander.Kolbasov@Sun.COM splx(save_spl);
48511389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
48611389SAlexander.Kolbasov@Sun.COM
4870Sstevel@tonic-gate if (copyout(set->ks_data, buf,
4880Sstevel@tonic-gate set->ks_nreqs * sizeof (uint64_t)) == -1)
4890Sstevel@tonic-gate return (EFAULT);
4900Sstevel@tonic-gate if (copyout(&ctx->kc_hrtime, hrtime, sizeof (uint64_t)) == -1)
4910Sstevel@tonic-gate return (EFAULT);
4920Sstevel@tonic-gate if (copyout(&ctx->kc_vtick, tick, sizeof (uint64_t)) == -1)
4930Sstevel@tonic-gate return (EFAULT);
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate return (0);
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate /*
4990Sstevel@tonic-gate * Stop the counters on the CPU this context is bound to.
5000Sstevel@tonic-gate */
5010Sstevel@tonic-gate static void
kcpc_stop_hw(kcpc_ctx_t * ctx)5020Sstevel@tonic-gate kcpc_stop_hw(kcpc_ctx_t *ctx)
5030Sstevel@tonic-gate {
5040Sstevel@tonic-gate cpu_t *cp;
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate kpreempt_disable();
5070Sstevel@tonic-gate
50811389SAlexander.Kolbasov@Sun.COM if (ctx->kc_cpuid == CPU->cpu_id) {
50911389SAlexander.Kolbasov@Sun.COM cp = CPU;
51011389SAlexander.Kolbasov@Sun.COM } else {
51111389SAlexander.Kolbasov@Sun.COM cp = cpu_get(ctx->kc_cpuid);
51211389SAlexander.Kolbasov@Sun.COM }
5130Sstevel@tonic-gate
51411389SAlexander.Kolbasov@Sun.COM ASSERT(cp != NULL && cp->cpu_cpc_ctx == ctx);
51511389SAlexander.Kolbasov@Sun.COM kcpc_cpu_stop(cp, B_FALSE);
51611389SAlexander.Kolbasov@Sun.COM
5170Sstevel@tonic-gate kpreempt_enable();
5180Sstevel@tonic-gate }
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate int
kcpc_unbind(kcpc_set_t * set)5210Sstevel@tonic-gate kcpc_unbind(kcpc_set_t *set)
5220Sstevel@tonic-gate {
5236275Strevtom kcpc_ctx_t *ctx;
5240Sstevel@tonic-gate kthread_t *t;
5250Sstevel@tonic-gate
5266275Strevtom /*
5276275Strevtom * We could be racing with the process's agent thread as it
5286275Strevtom * binds the set; we must wait for the set to finish binding
5296275Strevtom * before attempting to tear it down.
5306275Strevtom */
5316275Strevtom mutex_enter(&set->ks_lock);
5326275Strevtom while ((set->ks_state & KCPC_SET_BOUND) == 0)
5336275Strevtom cv_wait(&set->ks_condv, &set->ks_lock);
5346275Strevtom mutex_exit(&set->ks_lock);
5350Sstevel@tonic-gate
5366275Strevtom ctx = set->ks_ctx;
5376275Strevtom
5386275Strevtom /*
5396275Strevtom * Use kc_lock to synchronize with kcpc_restore().
5406275Strevtom */
5416275Strevtom mutex_enter(&ctx->kc_lock);
54211389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_INVALID);
5436275Strevtom mutex_exit(&ctx->kc_lock);
5440Sstevel@tonic-gate
5450Sstevel@tonic-gate if (ctx->kc_cpuid == -1) {
5460Sstevel@tonic-gate t = ctx->kc_thread;
5470Sstevel@tonic-gate /*
5480Sstevel@tonic-gate * The context is thread-bound and therefore has a device
5490Sstevel@tonic-gate * context. It will be freed via removectx() calling
5500Sstevel@tonic-gate * freectx() calling kcpc_free().
5510Sstevel@tonic-gate */
55211389SAlexander.Kolbasov@Sun.COM if (t == curthread) {
55311389SAlexander.Kolbasov@Sun.COM int save_spl;
55411389SAlexander.Kolbasov@Sun.COM
5550Sstevel@tonic-gate kpreempt_disable();
55611389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall();
55711389SAlexander.Kolbasov@Sun.COM if (!(ctx->kc_flags & KCPC_CTX_INVALID_STOPPED))
55811389SAlexander.Kolbasov@Sun.COM kcpc_unprogram(ctx, B_TRUE);
55911389SAlexander.Kolbasov@Sun.COM splx(save_spl);
5600Sstevel@tonic-gate kpreempt_enable();
5610Sstevel@tonic-gate }
5620Sstevel@tonic-gate #ifdef DEBUG
5630Sstevel@tonic-gate if (removectx(t, ctx, kcpc_save, kcpc_restore, NULL,
5640Sstevel@tonic-gate kcpc_lwp_create, NULL, kcpc_free) == 0)
5650Sstevel@tonic-gate panic("kcpc_unbind: context %p not preset on thread %p",
5667632SNick.Todd@Sun.COM (void *)ctx, (void *)t);
5670Sstevel@tonic-gate #else
5680Sstevel@tonic-gate (void) removectx(t, ctx, kcpc_save, kcpc_restore, NULL,
5690Sstevel@tonic-gate kcpc_lwp_create, NULL, kcpc_free);
5700Sstevel@tonic-gate #endif /* DEBUG */
5710Sstevel@tonic-gate t->t_cpc_set = NULL;
5720Sstevel@tonic-gate t->t_cpc_ctx = NULL;
5730Sstevel@tonic-gate } else {
5740Sstevel@tonic-gate /*
5750Sstevel@tonic-gate * If we are unbinding a CPU-bound set from a remote CPU, the
5760Sstevel@tonic-gate * native CPU's idle thread could be in the midst of programming
5770Sstevel@tonic-gate * this context onto the CPU. We grab the context's lock here to
5780Sstevel@tonic-gate * ensure that the idle thread is done with it. When we release
5790Sstevel@tonic-gate * the lock, the CPU no longer has a context and the idle thread
5800Sstevel@tonic-gate * will move on.
5810Sstevel@tonic-gate *
5820Sstevel@tonic-gate * cpu_lock must be held to prevent the CPU from being DR'd out
5830Sstevel@tonic-gate * while we disassociate the context from the cpu_t.
5840Sstevel@tonic-gate */
5850Sstevel@tonic-gate cpu_t *cp;
5860Sstevel@tonic-gate mutex_enter(&cpu_lock);
5870Sstevel@tonic-gate cp = cpu_get(ctx->kc_cpuid);
5880Sstevel@tonic-gate if (cp != NULL) {
5890Sstevel@tonic-gate /*
5900Sstevel@tonic-gate * The CPU may have been DR'd out of the system.
5910Sstevel@tonic-gate */
5920Sstevel@tonic-gate mutex_enter(&cp->cpu_cpc_ctxlock);
5930Sstevel@tonic-gate if ((ctx->kc_flags & KCPC_CTX_INVALID_STOPPED) == 0)
5940Sstevel@tonic-gate kcpc_stop_hw(ctx);
5950Sstevel@tonic-gate ASSERT(ctx->kc_flags & KCPC_CTX_INVALID_STOPPED);
5960Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock);
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate mutex_exit(&cpu_lock);
5990Sstevel@tonic-gate if (ctx->kc_thread == curthread) {
6000Sstevel@tonic-gate kcpc_free(ctx, 0);
6010Sstevel@tonic-gate curthread->t_cpc_set = NULL;
6020Sstevel@tonic-gate }
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate
6050Sstevel@tonic-gate return (0);
6060Sstevel@tonic-gate }
6070Sstevel@tonic-gate
6080Sstevel@tonic-gate int
kcpc_preset(kcpc_set_t * set,int index,uint64_t preset)6090Sstevel@tonic-gate kcpc_preset(kcpc_set_t *set, int index, uint64_t preset)
6100Sstevel@tonic-gate {
6110Sstevel@tonic-gate int i;
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate ASSERT(set != NULL);
6146275Strevtom ASSERT(set->ks_state & KCPC_SET_BOUND);
6150Sstevel@tonic-gate ASSERT(set->ks_ctx->kc_thread == curthread);
6160Sstevel@tonic-gate ASSERT(set->ks_ctx->kc_cpuid == -1);
6170Sstevel@tonic-gate
6180Sstevel@tonic-gate if (index < 0 || index >= set->ks_nreqs)
6190Sstevel@tonic-gate return (EINVAL);
6200Sstevel@tonic-gate
6210Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++)
6220Sstevel@tonic-gate if (set->ks_req[i].kr_index == index)
6230Sstevel@tonic-gate break;
6240Sstevel@tonic-gate ASSERT(i != set->ks_nreqs);
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate set->ks_req[i].kr_preset = preset;
6270Sstevel@tonic-gate return (0);
6280Sstevel@tonic-gate }
6290Sstevel@tonic-gate
6300Sstevel@tonic-gate int
kcpc_restart(kcpc_set_t * set)6310Sstevel@tonic-gate kcpc_restart(kcpc_set_t *set)
6320Sstevel@tonic-gate {
6330Sstevel@tonic-gate kcpc_ctx_t *ctx = set->ks_ctx;
6340Sstevel@tonic-gate int i;
63511389SAlexander.Kolbasov@Sun.COM int save_spl;
6360Sstevel@tonic-gate
6376275Strevtom ASSERT(set->ks_state & KCPC_SET_BOUND);
6380Sstevel@tonic-gate ASSERT(ctx->kc_thread == curthread);
6390Sstevel@tonic-gate ASSERT(ctx->kc_cpuid == -1);
6400Sstevel@tonic-gate
64111389SAlexander.Kolbasov@Sun.COM for (i = 0; i < set->ks_nreqs; i++) {
64211389SAlexander.Kolbasov@Sun.COM *(set->ks_req[i].kr_data) = set->ks_req[i].kr_preset;
64311389SAlexander.Kolbasov@Sun.COM pcbe_ops->pcbe_configure(0, NULL, set->ks_req[i].kr_preset,
64411389SAlexander.Kolbasov@Sun.COM 0, 0, NULL, &set->ks_req[i].kr_config, NULL);
64511389SAlexander.Kolbasov@Sun.COM }
64611389SAlexander.Kolbasov@Sun.COM
6470Sstevel@tonic-gate kpreempt_disable();
64811389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall();
6490Sstevel@tonic-gate
6500Sstevel@tonic-gate /*
6510Sstevel@tonic-gate * If the user is doing this on a running set, make sure the counters
6520Sstevel@tonic-gate * are stopped first.
6530Sstevel@tonic-gate */
6540Sstevel@tonic-gate if ((ctx->kc_flags & KCPC_CTX_FREEZE) == 0)
6550Sstevel@tonic-gate pcbe_ops->pcbe_allstop();
6560Sstevel@tonic-gate
6570Sstevel@tonic-gate /*
6580Sstevel@tonic-gate * Ask the backend to program the hardware.
6590Sstevel@tonic-gate */
6600Sstevel@tonic-gate ctx->kc_rawtick = KCPC_GET_TICK();
66111389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_CLR(ctx, KCPC_CTX_FREEZE);
6620Sstevel@tonic-gate pcbe_ops->pcbe_program(ctx);
66311389SAlexander.Kolbasov@Sun.COM splx(save_spl);
6640Sstevel@tonic-gate kpreempt_enable();
6650Sstevel@tonic-gate
6660Sstevel@tonic-gate return (0);
6670Sstevel@tonic-gate }
6680Sstevel@tonic-gate
6690Sstevel@tonic-gate /*
6700Sstevel@tonic-gate * Caller must hold kcpc_cpuctx_lock.
6710Sstevel@tonic-gate */
6720Sstevel@tonic-gate int
kcpc_enable(kthread_t * t,int cmd,int enable)6730Sstevel@tonic-gate kcpc_enable(kthread_t *t, int cmd, int enable)
6740Sstevel@tonic-gate {
6750Sstevel@tonic-gate kcpc_ctx_t *ctx = t->t_cpc_ctx;
6760Sstevel@tonic-gate kcpc_set_t *set = t->t_cpc_set;
6770Sstevel@tonic-gate kcpc_set_t *newset;
6780Sstevel@tonic-gate int i;
6790Sstevel@tonic-gate int flag;
6800Sstevel@tonic-gate int err;
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate ASSERT(RW_READ_HELD(&kcpc_cpuctx_lock));
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate if (ctx == NULL) {
6850Sstevel@tonic-gate /*
6860Sstevel@tonic-gate * This thread has a set but no context; it must be a
6870Sstevel@tonic-gate * CPU-bound set.
6880Sstevel@tonic-gate */
6890Sstevel@tonic-gate ASSERT(t->t_cpc_set != NULL);
6900Sstevel@tonic-gate ASSERT(t->t_cpc_set->ks_ctx->kc_cpuid != -1);
6910Sstevel@tonic-gate return (EINVAL);
6920Sstevel@tonic-gate } else if (ctx->kc_flags & KCPC_CTX_INVALID)
6930Sstevel@tonic-gate return (EAGAIN);
6940Sstevel@tonic-gate
6950Sstevel@tonic-gate if (cmd == CPC_ENABLE) {
6960Sstevel@tonic-gate if ((ctx->kc_flags & KCPC_CTX_FREEZE) == 0)
6970Sstevel@tonic-gate return (EINVAL);
6980Sstevel@tonic-gate kpreempt_disable();
69911389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_CLR(ctx, KCPC_CTX_FREEZE);
7000Sstevel@tonic-gate kcpc_restore(ctx);
7010Sstevel@tonic-gate kpreempt_enable();
7020Sstevel@tonic-gate } else if (cmd == CPC_DISABLE) {
7030Sstevel@tonic-gate if (ctx->kc_flags & KCPC_CTX_FREEZE)
7040Sstevel@tonic-gate return (EINVAL);
7050Sstevel@tonic-gate kpreempt_disable();
7060Sstevel@tonic-gate kcpc_save(ctx);
70711389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_FREEZE);
7080Sstevel@tonic-gate kpreempt_enable();
7090Sstevel@tonic-gate } else if (cmd == CPC_USR_EVENTS || cmd == CPC_SYS_EVENTS) {
7100Sstevel@tonic-gate /*
7110Sstevel@tonic-gate * Strategy for usr/sys: stop counters and update set's presets
7120Sstevel@tonic-gate * with current counter values, unbind, update requests with
7130Sstevel@tonic-gate * new config, then re-bind.
7140Sstevel@tonic-gate */
7150Sstevel@tonic-gate flag = (cmd == CPC_USR_EVENTS) ?
7160Sstevel@tonic-gate CPC_COUNT_USER: CPC_COUNT_SYSTEM;
7170Sstevel@tonic-gate
7180Sstevel@tonic-gate kpreempt_disable();
71911389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx,
7200Sstevel@tonic-gate KCPC_CTX_INVALID | KCPC_CTX_INVALID_STOPPED);
7210Sstevel@tonic-gate pcbe_ops->pcbe_allstop();
7220Sstevel@tonic-gate kpreempt_enable();
72311389SAlexander.Kolbasov@Sun.COM
7240Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++) {
7250Sstevel@tonic-gate set->ks_req[i].kr_preset = *(set->ks_req[i].kr_data);
7260Sstevel@tonic-gate if (enable)
7270Sstevel@tonic-gate set->ks_req[i].kr_flags |= flag;
7280Sstevel@tonic-gate else
7290Sstevel@tonic-gate set->ks_req[i].kr_flags &= ~flag;
7300Sstevel@tonic-gate }
7310Sstevel@tonic-gate newset = kcpc_dup_set(set);
7320Sstevel@tonic-gate if (kcpc_unbind(set) != 0)
7330Sstevel@tonic-gate return (EINVAL);
7340Sstevel@tonic-gate t->t_cpc_set = newset;
7350Sstevel@tonic-gate if (kcpc_bind_thread(newset, t, &err) != 0) {
7360Sstevel@tonic-gate t->t_cpc_set = NULL;
7370Sstevel@tonic-gate kcpc_free_set(newset);
7380Sstevel@tonic-gate return (EINVAL);
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate } else
7410Sstevel@tonic-gate return (EINVAL);
7420Sstevel@tonic-gate
7430Sstevel@tonic-gate return (0);
7440Sstevel@tonic-gate }
7450Sstevel@tonic-gate
7460Sstevel@tonic-gate /*
7470Sstevel@tonic-gate * Provide PCBEs with a way of obtaining the configs of every counter which will
7480Sstevel@tonic-gate * be programmed together.
7490Sstevel@tonic-gate *
7500Sstevel@tonic-gate * If current is NULL, provide the first config.
7510Sstevel@tonic-gate *
7520Sstevel@tonic-gate * If data != NULL, caller wants to know where the data store associated with
7530Sstevel@tonic-gate * the config we return is located.
7540Sstevel@tonic-gate */
7550Sstevel@tonic-gate void *
kcpc_next_config(void * token,void * current,uint64_t ** data)7560Sstevel@tonic-gate kcpc_next_config(void *token, void *current, uint64_t **data)
7570Sstevel@tonic-gate {
7580Sstevel@tonic-gate int i;
7590Sstevel@tonic-gate kcpc_pic_t *pic;
7600Sstevel@tonic-gate kcpc_ctx_t *ctx = (kcpc_ctx_t *)token;
7610Sstevel@tonic-gate
7620Sstevel@tonic-gate if (current == NULL) {
7630Sstevel@tonic-gate /*
7640Sstevel@tonic-gate * Client would like the first config, which may not be in
7650Sstevel@tonic-gate * counter 0; we need to search through the counters for the
7660Sstevel@tonic-gate * first config.
7670Sstevel@tonic-gate */
7680Sstevel@tonic-gate for (i = 0; i < cpc_ncounters; i++)
7690Sstevel@tonic-gate if (ctx->kc_pics[i].kp_req != NULL)
7700Sstevel@tonic-gate break;
7710Sstevel@tonic-gate /*
7720Sstevel@tonic-gate * There are no counters configured for the given context.
7730Sstevel@tonic-gate */
7740Sstevel@tonic-gate if (i == cpc_ncounters)
7750Sstevel@tonic-gate return (NULL);
7760Sstevel@tonic-gate } else {
7770Sstevel@tonic-gate /*
7780Sstevel@tonic-gate * There surely is a faster way to do this.
7790Sstevel@tonic-gate */
7800Sstevel@tonic-gate for (i = 0; i < cpc_ncounters; i++) {
7810Sstevel@tonic-gate pic = &ctx->kc_pics[i];
7820Sstevel@tonic-gate
7830Sstevel@tonic-gate if (pic->kp_req != NULL &&
7840Sstevel@tonic-gate current == pic->kp_req->kr_config)
7850Sstevel@tonic-gate break;
7860Sstevel@tonic-gate }
7870Sstevel@tonic-gate
7880Sstevel@tonic-gate /*
7890Sstevel@tonic-gate * We found the current config at picnum i. Now search for the
7900Sstevel@tonic-gate * next configured PIC.
7910Sstevel@tonic-gate */
7920Sstevel@tonic-gate for (i++; i < cpc_ncounters; i++) {
7930Sstevel@tonic-gate pic = &ctx->kc_pics[i];
7940Sstevel@tonic-gate if (pic->kp_req != NULL)
7950Sstevel@tonic-gate break;
7960Sstevel@tonic-gate }
7970Sstevel@tonic-gate
7980Sstevel@tonic-gate if (i == cpc_ncounters)
7990Sstevel@tonic-gate return (NULL);
8000Sstevel@tonic-gate }
8010Sstevel@tonic-gate
8020Sstevel@tonic-gate if (data != NULL) {
8030Sstevel@tonic-gate *data = ctx->kc_pics[i].kp_req->kr_data;
8040Sstevel@tonic-gate }
8050Sstevel@tonic-gate
8060Sstevel@tonic-gate return (ctx->kc_pics[i].kp_req->kr_config);
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate
8090Sstevel@tonic-gate
8108803SJonathan.Haslam@Sun.COM kcpc_ctx_t *
kcpc_ctx_alloc(int kmem_flags)81111389SAlexander.Kolbasov@Sun.COM kcpc_ctx_alloc(int kmem_flags)
8120Sstevel@tonic-gate {
8130Sstevel@tonic-gate kcpc_ctx_t *ctx;
8140Sstevel@tonic-gate long hash;
8150Sstevel@tonic-gate
81611389SAlexander.Kolbasov@Sun.COM ctx = (kcpc_ctx_t *)kmem_zalloc(sizeof (kcpc_ctx_t), kmem_flags);
81711389SAlexander.Kolbasov@Sun.COM if (ctx == NULL)
81811389SAlexander.Kolbasov@Sun.COM return (NULL);
8190Sstevel@tonic-gate
8200Sstevel@tonic-gate hash = CPC_HASH_CTX(ctx);
8210Sstevel@tonic-gate mutex_enter(&kcpc_ctx_llock[hash]);
8220Sstevel@tonic-gate ctx->kc_next = kcpc_ctx_list[hash];
8230Sstevel@tonic-gate kcpc_ctx_list[hash] = ctx;
8240Sstevel@tonic-gate mutex_exit(&kcpc_ctx_llock[hash]);
8250Sstevel@tonic-gate
8260Sstevel@tonic-gate ctx->kc_pics = (kcpc_pic_t *)kmem_zalloc(sizeof (kcpc_pic_t) *
8270Sstevel@tonic-gate cpc_ncounters, KM_SLEEP);
8280Sstevel@tonic-gate
8290Sstevel@tonic-gate ctx->kc_cpuid = -1;
8300Sstevel@tonic-gate
8310Sstevel@tonic-gate return (ctx);
8320Sstevel@tonic-gate }
8330Sstevel@tonic-gate
8340Sstevel@tonic-gate /*
8350Sstevel@tonic-gate * Copy set from ctx to the child context, cctx, if it has CPC_BIND_LWP_INHERIT
8360Sstevel@tonic-gate * in the flags.
8370Sstevel@tonic-gate */
8380Sstevel@tonic-gate static void
kcpc_ctx_clone(kcpc_ctx_t * ctx,kcpc_ctx_t * cctx)8390Sstevel@tonic-gate kcpc_ctx_clone(kcpc_ctx_t *ctx, kcpc_ctx_t *cctx)
8400Sstevel@tonic-gate {
8410Sstevel@tonic-gate kcpc_set_t *ks = ctx->kc_set, *cks;
8420Sstevel@tonic-gate int i, j;
8430Sstevel@tonic-gate int code;
8440Sstevel@tonic-gate
8450Sstevel@tonic-gate ASSERT(ks != NULL);
8460Sstevel@tonic-gate
8470Sstevel@tonic-gate if ((ks->ks_flags & CPC_BIND_LWP_INHERIT) == 0)
8480Sstevel@tonic-gate return;
8490Sstevel@tonic-gate
8506275Strevtom cks = kmem_zalloc(sizeof (*cks), KM_SLEEP);
8516275Strevtom cks->ks_state &= ~KCPC_SET_BOUND;
8520Sstevel@tonic-gate cctx->kc_set = cks;
8530Sstevel@tonic-gate cks->ks_flags = ks->ks_flags;
8540Sstevel@tonic-gate cks->ks_nreqs = ks->ks_nreqs;
8550Sstevel@tonic-gate cks->ks_req = kmem_alloc(cks->ks_nreqs *
8560Sstevel@tonic-gate sizeof (kcpc_request_t), KM_SLEEP);
8570Sstevel@tonic-gate cks->ks_data = kmem_alloc(cks->ks_nreqs * sizeof (uint64_t),
8580Sstevel@tonic-gate KM_SLEEP);
8590Sstevel@tonic-gate cks->ks_ctx = cctx;
8600Sstevel@tonic-gate
8610Sstevel@tonic-gate for (i = 0; i < cks->ks_nreqs; i++) {
8620Sstevel@tonic-gate cks->ks_req[i].kr_index = ks->ks_req[i].kr_index;
8630Sstevel@tonic-gate cks->ks_req[i].kr_picnum = ks->ks_req[i].kr_picnum;
8640Sstevel@tonic-gate (void) strncpy(cks->ks_req[i].kr_event,
8650Sstevel@tonic-gate ks->ks_req[i].kr_event, CPC_MAX_EVENT_LEN);
8660Sstevel@tonic-gate cks->ks_req[i].kr_preset = ks->ks_req[i].kr_preset;
8670Sstevel@tonic-gate cks->ks_req[i].kr_flags = ks->ks_req[i].kr_flags;
8680Sstevel@tonic-gate cks->ks_req[i].kr_nattrs = ks->ks_req[i].kr_nattrs;
8690Sstevel@tonic-gate if (ks->ks_req[i].kr_nattrs > 0) {
8700Sstevel@tonic-gate cks->ks_req[i].kr_attr =
8710Sstevel@tonic-gate kmem_alloc(ks->ks_req[i].kr_nattrs *
8725254Sgavinm sizeof (kcpc_attr_t), KM_SLEEP);
8730Sstevel@tonic-gate }
8740Sstevel@tonic-gate for (j = 0; j < ks->ks_req[i].kr_nattrs; j++) {
8750Sstevel@tonic-gate (void) strncpy(cks->ks_req[i].kr_attr[j].ka_name,
8760Sstevel@tonic-gate ks->ks_req[i].kr_attr[j].ka_name,
8770Sstevel@tonic-gate CPC_MAX_ATTR_LEN);
8780Sstevel@tonic-gate cks->ks_req[i].kr_attr[j].ka_val =
8790Sstevel@tonic-gate ks->ks_req[i].kr_attr[j].ka_val;
8800Sstevel@tonic-gate }
8810Sstevel@tonic-gate }
8820Sstevel@tonic-gate if (kcpc_configure_reqs(cctx, cks, &code) != 0)
8833732Sae112802 kcpc_invalidate_config(cctx);
8846275Strevtom
8856275Strevtom mutex_enter(&cks->ks_lock);
8866275Strevtom cks->ks_state |= KCPC_SET_BOUND;
8876275Strevtom cv_signal(&cks->ks_condv);
8886275Strevtom mutex_exit(&cks->ks_lock);
8890Sstevel@tonic-gate }
8900Sstevel@tonic-gate
8910Sstevel@tonic-gate
8928803SJonathan.Haslam@Sun.COM void
kcpc_ctx_free(kcpc_ctx_t * ctx)8930Sstevel@tonic-gate kcpc_ctx_free(kcpc_ctx_t *ctx)
8940Sstevel@tonic-gate {
8950Sstevel@tonic-gate kcpc_ctx_t **loc;
8960Sstevel@tonic-gate long hash = CPC_HASH_CTX(ctx);
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate mutex_enter(&kcpc_ctx_llock[hash]);
8990Sstevel@tonic-gate loc = &kcpc_ctx_list[hash];
9000Sstevel@tonic-gate ASSERT(*loc != NULL);
9010Sstevel@tonic-gate while (*loc != ctx)
9020Sstevel@tonic-gate loc = &(*loc)->kc_next;
9030Sstevel@tonic-gate *loc = ctx->kc_next;
9040Sstevel@tonic-gate mutex_exit(&kcpc_ctx_llock[hash]);
9050Sstevel@tonic-gate
9060Sstevel@tonic-gate kmem_free(ctx->kc_pics, cpc_ncounters * sizeof (kcpc_pic_t));
9076275Strevtom cv_destroy(&ctx->kc_condv);
9086275Strevtom mutex_destroy(&ctx->kc_lock);
9090Sstevel@tonic-gate kmem_free(ctx, sizeof (*ctx));
9100Sstevel@tonic-gate }
9110Sstevel@tonic-gate
9120Sstevel@tonic-gate /*
9130Sstevel@tonic-gate * Generic interrupt handler used on hardware that generates
9140Sstevel@tonic-gate * overflow interrupts.
9150Sstevel@tonic-gate *
9160Sstevel@tonic-gate * Note: executed at high-level interrupt context!
9170Sstevel@tonic-gate */
9180Sstevel@tonic-gate /*ARGSUSED*/
9190Sstevel@tonic-gate kcpc_ctx_t *
kcpc_overflow_intr(caddr_t arg,uint64_t bitmap)9200Sstevel@tonic-gate kcpc_overflow_intr(caddr_t arg, uint64_t bitmap)
9210Sstevel@tonic-gate {
9220Sstevel@tonic-gate kcpc_ctx_t *ctx;
9230Sstevel@tonic-gate kthread_t *t = curthread;
9240Sstevel@tonic-gate int i;
9250Sstevel@tonic-gate
9260Sstevel@tonic-gate /*
9270Sstevel@tonic-gate * On both x86 and UltraSPARC, we may deliver the high-level
9280Sstevel@tonic-gate * interrupt in kernel mode, just after we've started to run an
9290Sstevel@tonic-gate * interrupt thread. (That's because the hardware helpfully
9300Sstevel@tonic-gate * delivers the overflow interrupt some random number of cycles
9310Sstevel@tonic-gate * after the instruction that caused the overflow by which time
9320Sstevel@tonic-gate * we're in some part of the kernel, not necessarily running on
9330Sstevel@tonic-gate * the right thread).
9340Sstevel@tonic-gate *
9350Sstevel@tonic-gate * Check for this case here -- find the pinned thread
9360Sstevel@tonic-gate * that was running when the interrupt went off.
9370Sstevel@tonic-gate */
9380Sstevel@tonic-gate if (t->t_flag & T_INTR_THREAD) {
9390Sstevel@tonic-gate klwp_t *lwp;
9400Sstevel@tonic-gate
9410Sstevel@tonic-gate atomic_add_32(&kcpc_intrctx_count, 1);
9420Sstevel@tonic-gate
9430Sstevel@tonic-gate /*
9440Sstevel@tonic-gate * Note that t_lwp is always set to point at the underlying
9450Sstevel@tonic-gate * thread, thus this will work in the presence of nested
9460Sstevel@tonic-gate * interrupts.
9470Sstevel@tonic-gate */
9480Sstevel@tonic-gate ctx = NULL;
9490Sstevel@tonic-gate if ((lwp = t->t_lwp) != NULL) {
9500Sstevel@tonic-gate t = lwptot(lwp);
9510Sstevel@tonic-gate ctx = t->t_cpc_ctx;
9520Sstevel@tonic-gate }
9530Sstevel@tonic-gate } else
9540Sstevel@tonic-gate ctx = t->t_cpc_ctx;
9550Sstevel@tonic-gate
9560Sstevel@tonic-gate if (ctx == NULL) {
9570Sstevel@tonic-gate /*
9580Sstevel@tonic-gate * This can easily happen if we're using the counters in
9590Sstevel@tonic-gate * "shared" mode, for example, and an overflow interrupt
9600Sstevel@tonic-gate * occurs while we are running cpustat. In that case, the
9610Sstevel@tonic-gate * bound thread that has the context that belongs to this
9620Sstevel@tonic-gate * CPU is almost certainly sleeping (if it was running on
9630Sstevel@tonic-gate * the CPU we'd have found it above), and the actual
9640Sstevel@tonic-gate * interrupted thread has no knowledge of performance counters!
9650Sstevel@tonic-gate */
9660Sstevel@tonic-gate ctx = curthread->t_cpu->cpu_cpc_ctx;
9670Sstevel@tonic-gate if (ctx != NULL) {
9680Sstevel@tonic-gate /*
9690Sstevel@tonic-gate * Return the bound context for this CPU to
9700Sstevel@tonic-gate * the interrupt handler so that it can synchronously
9710Sstevel@tonic-gate * sample the hardware counters and restart them.
9720Sstevel@tonic-gate */
9730Sstevel@tonic-gate return (ctx);
9740Sstevel@tonic-gate }
9750Sstevel@tonic-gate
9760Sstevel@tonic-gate /*
9770Sstevel@tonic-gate * As long as the overflow interrupt really is delivered early
9780Sstevel@tonic-gate * enough after trapping into the kernel to avoid switching
9790Sstevel@tonic-gate * threads, we must always be able to find the cpc context,
9800Sstevel@tonic-gate * or something went terribly wrong i.e. we ended up
9810Sstevel@tonic-gate * running a passivated interrupt thread, a kernel
9820Sstevel@tonic-gate * thread or we interrupted idle, all of which are Very Bad.
9838803SJonathan.Haslam@Sun.COM *
9848803SJonathan.Haslam@Sun.COM * We also could end up here owing to an incredibly unlikely
9858803SJonathan.Haslam@Sun.COM * race condition that exists on x86 based architectures when
9868803SJonathan.Haslam@Sun.COM * the cpc provider is in use; overflow interrupts are directed
9878803SJonathan.Haslam@Sun.COM * to the cpc provider if the 'dtrace_cpc_in_use' variable is
9888803SJonathan.Haslam@Sun.COM * set when we enter the handler. This variable is unset after
9898803SJonathan.Haslam@Sun.COM * overflow interrupts have been disabled on all CPUs and all
9908803SJonathan.Haslam@Sun.COM * contexts have been torn down. To stop interrupts, the cpc
9918803SJonathan.Haslam@Sun.COM * provider issues a xcall to the remote CPU before it tears
9928803SJonathan.Haslam@Sun.COM * down that CPUs context. As high priority xcalls, on an x86
9938803SJonathan.Haslam@Sun.COM * architecture, execute at a higher PIL than this handler, it
9948803SJonathan.Haslam@Sun.COM * is possible (though extremely unlikely) that the xcall could
9958803SJonathan.Haslam@Sun.COM * interrupt the overflow handler before the handler has
9968803SJonathan.Haslam@Sun.COM * checked the 'dtrace_cpc_in_use' variable, stop the counters,
9978803SJonathan.Haslam@Sun.COM * return to the cpc provider which could then rip down
9988803SJonathan.Haslam@Sun.COM * contexts and unset 'dtrace_cpc_in_use' *before* the CPUs
9998803SJonathan.Haslam@Sun.COM * overflow handler has had a chance to check the variable. In
10008803SJonathan.Haslam@Sun.COM * that case, the handler would direct the overflow into this
10018803SJonathan.Haslam@Sun.COM * code and no valid context will be found. The default behavior
10028803SJonathan.Haslam@Sun.COM * when no valid context is found is now to shout a warning to
10038803SJonathan.Haslam@Sun.COM * the console and bump the 'kcpc_nullctx_count' variable.
10040Sstevel@tonic-gate */
10050Sstevel@tonic-gate if (kcpc_nullctx_panic)
10060Sstevel@tonic-gate panic("null cpc context, thread %p", (void *)t);
100711389SAlexander.Kolbasov@Sun.COM #ifdef DEBUG
100811389SAlexander.Kolbasov@Sun.COM cmn_err(CE_NOTE,
10098803SJonathan.Haslam@Sun.COM "null cpc context found in overflow handler!\n");
101011389SAlexander.Kolbasov@Sun.COM #endif
10110Sstevel@tonic-gate atomic_add_32(&kcpc_nullctx_count, 1);
10120Sstevel@tonic-gate } else if ((ctx->kc_flags & KCPC_CTX_INVALID) == 0) {
10130Sstevel@tonic-gate /*
10140Sstevel@tonic-gate * Schedule an ast to sample the counters, which will
10150Sstevel@tonic-gate * propagate any overflow into the virtualized performance
10160Sstevel@tonic-gate * counter(s), and may deliver a signal.
10170Sstevel@tonic-gate */
10180Sstevel@tonic-gate ttolwp(t)->lwp_pcb.pcb_flags |= CPC_OVERFLOW;
10190Sstevel@tonic-gate /*
10200Sstevel@tonic-gate * If a counter has overflowed which was counting on behalf of
10210Sstevel@tonic-gate * a request which specified CPC_OVF_NOTIFY_EMT, send the
10220Sstevel@tonic-gate * process a signal.
10230Sstevel@tonic-gate */
10240Sstevel@tonic-gate for (i = 0; i < cpc_ncounters; i++) {
10250Sstevel@tonic-gate if (ctx->kc_pics[i].kp_req != NULL &&
10260Sstevel@tonic-gate bitmap & (1 << i) &&
10270Sstevel@tonic-gate ctx->kc_pics[i].kp_req->kr_flags &
10280Sstevel@tonic-gate CPC_OVF_NOTIFY_EMT) {
10290Sstevel@tonic-gate /*
10300Sstevel@tonic-gate * A signal has been requested for this PIC, so
10310Sstevel@tonic-gate * so freeze the context. The interrupt handler
10320Sstevel@tonic-gate * has already stopped the counter hardware.
10330Sstevel@tonic-gate */
103411389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_FREEZE);
10350Sstevel@tonic-gate atomic_or_uint(&ctx->kc_pics[i].kp_flags,
10360Sstevel@tonic-gate KCPC_PIC_OVERFLOWED);
10370Sstevel@tonic-gate }
10380Sstevel@tonic-gate }
10390Sstevel@tonic-gate aston(t);
104011389SAlexander.Kolbasov@Sun.COM } else if (ctx->kc_flags & KCPC_CTX_INVALID_STOPPED) {
104111389SAlexander.Kolbasov@Sun.COM /*
104211389SAlexander.Kolbasov@Sun.COM * Thread context is no longer valid, but here may be a valid
104311389SAlexander.Kolbasov@Sun.COM * CPU context.
104411389SAlexander.Kolbasov@Sun.COM */
104511389SAlexander.Kolbasov@Sun.COM return (curthread->t_cpu->cpu_cpc_ctx);
10460Sstevel@tonic-gate }
104711389SAlexander.Kolbasov@Sun.COM
10480Sstevel@tonic-gate return (NULL);
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate
10510Sstevel@tonic-gate /*
10520Sstevel@tonic-gate * The current thread context had an overflow interrupt; we're
10530Sstevel@tonic-gate * executing here in high-level interrupt context.
10540Sstevel@tonic-gate */
10550Sstevel@tonic-gate /*ARGSUSED*/
10560Sstevel@tonic-gate uint_t
kcpc_hw_overflow_intr(caddr_t arg1,caddr_t arg2)10570Sstevel@tonic-gate kcpc_hw_overflow_intr(caddr_t arg1, caddr_t arg2)
10580Sstevel@tonic-gate {
10598803SJonathan.Haslam@Sun.COM kcpc_ctx_t *ctx;
10608803SJonathan.Haslam@Sun.COM uint64_t bitmap;
10618803SJonathan.Haslam@Sun.COM uint8_t *state;
106211389SAlexander.Kolbasov@Sun.COM int save_spl;
10630Sstevel@tonic-gate
10640Sstevel@tonic-gate if (pcbe_ops == NULL ||
10650Sstevel@tonic-gate (bitmap = pcbe_ops->pcbe_overflow_bitmap()) == 0)
10660Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED);
10673884Sha137994
10680Sstevel@tonic-gate /*
10690Sstevel@tonic-gate * Prevent any further interrupts.
10700Sstevel@tonic-gate */
10710Sstevel@tonic-gate pcbe_ops->pcbe_allstop();
10720Sstevel@tonic-gate
10738803SJonathan.Haslam@Sun.COM if (dtrace_cpc_in_use) {
10748803SJonathan.Haslam@Sun.COM state = &cpu_core[CPU->cpu_id].cpuc_dcpc_intr_state;
10758803SJonathan.Haslam@Sun.COM
10768803SJonathan.Haslam@Sun.COM /*
10778803SJonathan.Haslam@Sun.COM * Set the per-CPU state bit to indicate that we are currently
10788803SJonathan.Haslam@Sun.COM * processing an interrupt if it is currently free. Drop the
10798803SJonathan.Haslam@Sun.COM * interrupt if the state isn't free (i.e. a configuration
10808803SJonathan.Haslam@Sun.COM * event is taking place).
10818803SJonathan.Haslam@Sun.COM */
10828803SJonathan.Haslam@Sun.COM if (atomic_cas_8(state, DCPC_INTR_FREE,
10838803SJonathan.Haslam@Sun.COM DCPC_INTR_PROCESSING) == DCPC_INTR_FREE) {
10848803SJonathan.Haslam@Sun.COM int i;
10858803SJonathan.Haslam@Sun.COM kcpc_request_t req;
10868803SJonathan.Haslam@Sun.COM
10878803SJonathan.Haslam@Sun.COM ASSERT(dtrace_cpc_fire != NULL);
10888803SJonathan.Haslam@Sun.COM
10898803SJonathan.Haslam@Sun.COM (*dtrace_cpc_fire)(bitmap);
10908803SJonathan.Haslam@Sun.COM
10918803SJonathan.Haslam@Sun.COM ctx = curthread->t_cpu->cpu_cpc_ctx;
109211389SAlexander.Kolbasov@Sun.COM if (ctx == NULL) {
109311389SAlexander.Kolbasov@Sun.COM #ifdef DEBUG
109411389SAlexander.Kolbasov@Sun.COM cmn_err(CE_NOTE, "null cpc context in"
109511389SAlexander.Kolbasov@Sun.COM "hardware overflow handler!\n");
109611389SAlexander.Kolbasov@Sun.COM #endif
109711389SAlexander.Kolbasov@Sun.COM return (DDI_INTR_CLAIMED);
109811389SAlexander.Kolbasov@Sun.COM }
10998803SJonathan.Haslam@Sun.COM
11008803SJonathan.Haslam@Sun.COM /* Reset any counters that have overflowed */
11018803SJonathan.Haslam@Sun.COM for (i = 0; i < ctx->kc_set->ks_nreqs; i++) {
11028803SJonathan.Haslam@Sun.COM req = ctx->kc_set->ks_req[i];
11038803SJonathan.Haslam@Sun.COM
11048803SJonathan.Haslam@Sun.COM if (bitmap & (1 << req.kr_picnum)) {
11058803SJonathan.Haslam@Sun.COM pcbe_ops->pcbe_configure(req.kr_picnum,
11068803SJonathan.Haslam@Sun.COM req.kr_event, req.kr_preset,
11078803SJonathan.Haslam@Sun.COM req.kr_flags, req.kr_nattrs,
11088803SJonathan.Haslam@Sun.COM req.kr_attr, &(req.kr_config),
11098803SJonathan.Haslam@Sun.COM (void *)ctx);
11108803SJonathan.Haslam@Sun.COM }
11118803SJonathan.Haslam@Sun.COM }
11128803SJonathan.Haslam@Sun.COM pcbe_ops->pcbe_program(ctx);
11138803SJonathan.Haslam@Sun.COM
11148803SJonathan.Haslam@Sun.COM /*
11158803SJonathan.Haslam@Sun.COM * We've finished processing the interrupt so set
11168803SJonathan.Haslam@Sun.COM * the state back to free.
11178803SJonathan.Haslam@Sun.COM */
11188803SJonathan.Haslam@Sun.COM cpu_core[CPU->cpu_id].cpuc_dcpc_intr_state =
11198803SJonathan.Haslam@Sun.COM DCPC_INTR_FREE;
11208803SJonathan.Haslam@Sun.COM membar_producer();
11218803SJonathan.Haslam@Sun.COM }
11228803SJonathan.Haslam@Sun.COM return (DDI_INTR_CLAIMED);
11238803SJonathan.Haslam@Sun.COM }
11248803SJonathan.Haslam@Sun.COM
11250Sstevel@tonic-gate /*
11268803SJonathan.Haslam@Sun.COM * DTrace isn't involved so pass on accordingly.
11270Sstevel@tonic-gate *
11280Sstevel@tonic-gate * If the interrupt has occurred in the context of an lwp owning
11290Sstevel@tonic-gate * the counters, then the handler posts an AST to the lwp to
11300Sstevel@tonic-gate * trigger the actual sampling, and optionally deliver a signal or
11310Sstevel@tonic-gate * restart the counters, on the way out of the kernel using
11320Sstevel@tonic-gate * kcpc_hw_overflow_ast() (see below).
11330Sstevel@tonic-gate *
11340Sstevel@tonic-gate * On the other hand, if the handler returns the context to us
11350Sstevel@tonic-gate * directly, then it means that there are no other threads in
11360Sstevel@tonic-gate * the middle of updating it, no AST has been posted, and so we
11370Sstevel@tonic-gate * should sample the counters here, and restart them with no
11380Sstevel@tonic-gate * further fuss.
113911389SAlexander.Kolbasov@Sun.COM *
114011389SAlexander.Kolbasov@Sun.COM * The CPU's CPC context may disappear as a result of cross-call which
114111389SAlexander.Kolbasov@Sun.COM * has higher PIL on x86, so protect the context by raising PIL to the
114211389SAlexander.Kolbasov@Sun.COM * cross-call level.
11430Sstevel@tonic-gate */
114411389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall();
11450Sstevel@tonic-gate if ((ctx = kcpc_overflow_intr(arg1, bitmap)) != NULL) {
11460Sstevel@tonic-gate uint64_t curtick = KCPC_GET_TICK();
11470Sstevel@tonic-gate
11480Sstevel@tonic-gate ctx->kc_hrtime = gethrtime_waitfree();
11490Sstevel@tonic-gate ctx->kc_vtick += curtick - ctx->kc_rawtick;
11500Sstevel@tonic-gate ctx->kc_rawtick = curtick;
11510Sstevel@tonic-gate pcbe_ops->pcbe_sample(ctx);
11520Sstevel@tonic-gate pcbe_ops->pcbe_program(ctx);
11530Sstevel@tonic-gate }
115411389SAlexander.Kolbasov@Sun.COM splx(save_spl);
11550Sstevel@tonic-gate
11560Sstevel@tonic-gate return (DDI_INTR_CLAIMED);
11570Sstevel@tonic-gate }
11580Sstevel@tonic-gate
11590Sstevel@tonic-gate /*
11600Sstevel@tonic-gate * Called from trap() when processing the ast posted by the high-level
11610Sstevel@tonic-gate * interrupt handler.
11620Sstevel@tonic-gate */
11630Sstevel@tonic-gate int
kcpc_overflow_ast()11640Sstevel@tonic-gate kcpc_overflow_ast()
11650Sstevel@tonic-gate {
11660Sstevel@tonic-gate kcpc_ctx_t *ctx = curthread->t_cpc_ctx;
11670Sstevel@tonic-gate int i;
11680Sstevel@tonic-gate int found = 0;
11690Sstevel@tonic-gate uint64_t curtick = KCPC_GET_TICK();
11700Sstevel@tonic-gate
11710Sstevel@tonic-gate ASSERT(ctx != NULL); /* Beware of interrupt skid. */
11720Sstevel@tonic-gate
11730Sstevel@tonic-gate /*
11740Sstevel@tonic-gate * An overflow happened: sample the context to ensure that
11750Sstevel@tonic-gate * the overflow is propagated into the upper bits of the
11760Sstevel@tonic-gate * virtualized 64-bit counter(s).
11770Sstevel@tonic-gate */
11780Sstevel@tonic-gate kpreempt_disable();
11790Sstevel@tonic-gate ctx->kc_hrtime = gethrtime_waitfree();
11800Sstevel@tonic-gate pcbe_ops->pcbe_sample(ctx);
11810Sstevel@tonic-gate kpreempt_enable();
11820Sstevel@tonic-gate
11830Sstevel@tonic-gate ctx->kc_vtick += curtick - ctx->kc_rawtick;
11840Sstevel@tonic-gate
11850Sstevel@tonic-gate /*
11860Sstevel@tonic-gate * The interrupt handler has marked any pics with KCPC_PIC_OVERFLOWED
11870Sstevel@tonic-gate * if that pic generated an overflow and if the request it was counting
11880Sstevel@tonic-gate * on behalf of had CPC_OVERFLOW_REQUEST specified. We go through all
11890Sstevel@tonic-gate * pics in the context and clear the KCPC_PIC_OVERFLOWED flags. If we
11900Sstevel@tonic-gate * found any overflowed pics, keep the context frozen and return true
11910Sstevel@tonic-gate * (thus causing a signal to be sent).
11920Sstevel@tonic-gate */
11930Sstevel@tonic-gate for (i = 0; i < cpc_ncounters; i++) {
11940Sstevel@tonic-gate if (ctx->kc_pics[i].kp_flags & KCPC_PIC_OVERFLOWED) {
11950Sstevel@tonic-gate atomic_and_uint(&ctx->kc_pics[i].kp_flags,
11960Sstevel@tonic-gate ~KCPC_PIC_OVERFLOWED);
11970Sstevel@tonic-gate found = 1;
11980Sstevel@tonic-gate }
11990Sstevel@tonic-gate }
12000Sstevel@tonic-gate if (found)
12010Sstevel@tonic-gate return (1);
12020Sstevel@tonic-gate
12030Sstevel@tonic-gate /*
12040Sstevel@tonic-gate * Otherwise, re-enable the counters and continue life as before.
12050Sstevel@tonic-gate */
12060Sstevel@tonic-gate kpreempt_disable();
120711389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_CLR(ctx, KCPC_CTX_FREEZE);
12080Sstevel@tonic-gate pcbe_ops->pcbe_program(ctx);
12090Sstevel@tonic-gate kpreempt_enable();
12100Sstevel@tonic-gate return (0);
12110Sstevel@tonic-gate }
12120Sstevel@tonic-gate
12130Sstevel@tonic-gate /*
12140Sstevel@tonic-gate * Called when switching away from current thread.
12150Sstevel@tonic-gate */
12160Sstevel@tonic-gate static void
kcpc_save(kcpc_ctx_t * ctx)12170Sstevel@tonic-gate kcpc_save(kcpc_ctx_t *ctx)
12180Sstevel@tonic-gate {
121911389SAlexander.Kolbasov@Sun.COM int err;
122011389SAlexander.Kolbasov@Sun.COM int save_spl;
122111389SAlexander.Kolbasov@Sun.COM
122211389SAlexander.Kolbasov@Sun.COM kpreempt_disable();
122311389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall();
122411389SAlexander.Kolbasov@Sun.COM
12250Sstevel@tonic-gate if (ctx->kc_flags & KCPC_CTX_INVALID) {
122611389SAlexander.Kolbasov@Sun.COM if (ctx->kc_flags & KCPC_CTX_INVALID_STOPPED) {
122711389SAlexander.Kolbasov@Sun.COM splx(save_spl);
122811389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
12290Sstevel@tonic-gate return;
123011389SAlexander.Kolbasov@Sun.COM }
12310Sstevel@tonic-gate /*
12320Sstevel@tonic-gate * This context has been invalidated but the counters have not
12330Sstevel@tonic-gate * been stopped. Stop them here and mark the context stopped.
12340Sstevel@tonic-gate */
123511389SAlexander.Kolbasov@Sun.COM kcpc_unprogram(ctx, B_TRUE);
123611389SAlexander.Kolbasov@Sun.COM splx(save_spl);
123711389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
12380Sstevel@tonic-gate return;
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate
12410Sstevel@tonic-gate pcbe_ops->pcbe_allstop();
124211389SAlexander.Kolbasov@Sun.COM if (ctx->kc_flags & KCPC_CTX_FREEZE) {
124311389SAlexander.Kolbasov@Sun.COM splx(save_spl);
124411389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
12450Sstevel@tonic-gate return;
124611389SAlexander.Kolbasov@Sun.COM }
12470Sstevel@tonic-gate
12480Sstevel@tonic-gate /*
12490Sstevel@tonic-gate * Need to sample for all reqs into each req's current mpic.
12500Sstevel@tonic-gate */
125111389SAlexander.Kolbasov@Sun.COM ctx->kc_hrtime = gethrtime_waitfree();
12520Sstevel@tonic-gate ctx->kc_vtick += KCPC_GET_TICK() - ctx->kc_rawtick;
12530Sstevel@tonic-gate pcbe_ops->pcbe_sample(ctx);
125411389SAlexander.Kolbasov@Sun.COM
125511389SAlexander.Kolbasov@Sun.COM /*
125611389SAlexander.Kolbasov@Sun.COM * Program counter for measuring capacity and utilization since user
125711389SAlexander.Kolbasov@Sun.COM * thread isn't using counter anymore
125811389SAlexander.Kolbasov@Sun.COM */
125911389SAlexander.Kolbasov@Sun.COM ASSERT(ctx->kc_cpuid == -1);
126011389SAlexander.Kolbasov@Sun.COM cu_cpc_program(CPU, &err);
126111389SAlexander.Kolbasov@Sun.COM splx(save_spl);
126211389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
12630Sstevel@tonic-gate }
12640Sstevel@tonic-gate
12650Sstevel@tonic-gate static void
kcpc_restore(kcpc_ctx_t * ctx)12660Sstevel@tonic-gate kcpc_restore(kcpc_ctx_t *ctx)
12670Sstevel@tonic-gate {
126811389SAlexander.Kolbasov@Sun.COM int save_spl;
126911389SAlexander.Kolbasov@Sun.COM
12706275Strevtom mutex_enter(&ctx->kc_lock);
127111389SAlexander.Kolbasov@Sun.COM
12720Sstevel@tonic-gate if ((ctx->kc_flags & (KCPC_CTX_INVALID | KCPC_CTX_INVALID_STOPPED)) ==
127311389SAlexander.Kolbasov@Sun.COM KCPC_CTX_INVALID) {
12740Sstevel@tonic-gate /*
12750Sstevel@tonic-gate * The context is invalidated but has not been marked stopped.
12760Sstevel@tonic-gate * We mark it as such here because we will not start the
12770Sstevel@tonic-gate * counters during this context switch.
12780Sstevel@tonic-gate */
127911389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_INVALID_STOPPED);
128011389SAlexander.Kolbasov@Sun.COM }
12810Sstevel@tonic-gate
12826275Strevtom if (ctx->kc_flags & (KCPC_CTX_INVALID | KCPC_CTX_FREEZE)) {
12836275Strevtom mutex_exit(&ctx->kc_lock);
12840Sstevel@tonic-gate return;
12856275Strevtom }
12866275Strevtom
12876275Strevtom /*
12886275Strevtom * Set kc_flags to show that a kcpc_restore() is in progress to avoid
12896275Strevtom * ctx & set related memory objects being freed without us knowing.
12906275Strevtom * This can happen if an agent thread is executing a kcpc_unbind(),
12916275Strevtom * with this thread as the target, whilst we're concurrently doing a
12926275Strevtom * restorectx() during, for example, a proc_exit(). Effectively, by
12936275Strevtom * doing this, we're asking kcpc_free() to cv_wait() until
12946275Strevtom * kcpc_restore() has completed.
12956275Strevtom */
129611389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_RESTORE);
12976275Strevtom mutex_exit(&ctx->kc_lock);
12980Sstevel@tonic-gate
12990Sstevel@tonic-gate /*
13000Sstevel@tonic-gate * While programming the hardware, the counters should be stopped. We
13010Sstevel@tonic-gate * don't do an explicit pcbe_allstop() here because they should have
13020Sstevel@tonic-gate * been stopped already by the last consumer.
13030Sstevel@tonic-gate */
130411389SAlexander.Kolbasov@Sun.COM kpreempt_disable();
130511389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall();
130611389SAlexander.Kolbasov@Sun.COM kcpc_program(ctx, B_TRUE, B_TRUE);
130711389SAlexander.Kolbasov@Sun.COM splx(save_spl);
130811389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
13096275Strevtom
13106275Strevtom /*
13116275Strevtom * Wake the agent thread if it's waiting in kcpc_free().
13126275Strevtom */
13136275Strevtom mutex_enter(&ctx->kc_lock);
131411389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_CLR(ctx, KCPC_CTX_RESTORE);
13156275Strevtom cv_signal(&ctx->kc_condv);
13166275Strevtom mutex_exit(&ctx->kc_lock);
13170Sstevel@tonic-gate }
13180Sstevel@tonic-gate
13190Sstevel@tonic-gate /*
13200Sstevel@tonic-gate * If kcpc_counts_include_idle is set to 0 by the sys admin, we add the the
13210Sstevel@tonic-gate * following context operators to the idle thread on each CPU. They stop the
13220Sstevel@tonic-gate * counters when the idle thread is switched on, and they start them again when
13230Sstevel@tonic-gate * it is switched off.
13240Sstevel@tonic-gate */
13250Sstevel@tonic-gate /*ARGSUSED*/
13260Sstevel@tonic-gate void
kcpc_idle_save(struct cpu * cp)13270Sstevel@tonic-gate kcpc_idle_save(struct cpu *cp)
13280Sstevel@tonic-gate {
13290Sstevel@tonic-gate /*
13300Sstevel@tonic-gate * The idle thread shouldn't be run anywhere else.
13310Sstevel@tonic-gate */
13320Sstevel@tonic-gate ASSERT(CPU == cp);
13330Sstevel@tonic-gate
13340Sstevel@tonic-gate /*
13350Sstevel@tonic-gate * We must hold the CPU's context lock to ensure the context isn't freed
13360Sstevel@tonic-gate * while we're looking at it.
13370Sstevel@tonic-gate */
13380Sstevel@tonic-gate mutex_enter(&cp->cpu_cpc_ctxlock);
13390Sstevel@tonic-gate
13400Sstevel@tonic-gate if ((cp->cpu_cpc_ctx == NULL) ||
13410Sstevel@tonic-gate (cp->cpu_cpc_ctx->kc_flags & KCPC_CTX_INVALID)) {
13420Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock);
13430Sstevel@tonic-gate return;
13440Sstevel@tonic-gate }
13450Sstevel@tonic-gate
13460Sstevel@tonic-gate pcbe_ops->pcbe_program(cp->cpu_cpc_ctx);
13470Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock);
13480Sstevel@tonic-gate }
13490Sstevel@tonic-gate
13500Sstevel@tonic-gate void
kcpc_idle_restore(struct cpu * cp)13510Sstevel@tonic-gate kcpc_idle_restore(struct cpu *cp)
13520Sstevel@tonic-gate {
13530Sstevel@tonic-gate /*
13540Sstevel@tonic-gate * The idle thread shouldn't be run anywhere else.
13550Sstevel@tonic-gate */
13560Sstevel@tonic-gate ASSERT(CPU == cp);
13570Sstevel@tonic-gate
13580Sstevel@tonic-gate /*
13590Sstevel@tonic-gate * We must hold the CPU's context lock to ensure the context isn't freed
13600Sstevel@tonic-gate * while we're looking at it.
13610Sstevel@tonic-gate */
13620Sstevel@tonic-gate mutex_enter(&cp->cpu_cpc_ctxlock);
13630Sstevel@tonic-gate
13640Sstevel@tonic-gate if ((cp->cpu_cpc_ctx == NULL) ||
13650Sstevel@tonic-gate (cp->cpu_cpc_ctx->kc_flags & KCPC_CTX_INVALID)) {
13660Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock);
13670Sstevel@tonic-gate return;
13680Sstevel@tonic-gate }
13690Sstevel@tonic-gate
13700Sstevel@tonic-gate pcbe_ops->pcbe_allstop();
13710Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock);
13720Sstevel@tonic-gate }
13730Sstevel@tonic-gate
13740Sstevel@tonic-gate /*ARGSUSED*/
13750Sstevel@tonic-gate static void
kcpc_lwp_create(kthread_t * t,kthread_t * ct)13760Sstevel@tonic-gate kcpc_lwp_create(kthread_t *t, kthread_t *ct)
13770Sstevel@tonic-gate {
13780Sstevel@tonic-gate kcpc_ctx_t *ctx = t->t_cpc_ctx, *cctx;
13790Sstevel@tonic-gate int i;
13800Sstevel@tonic-gate
13810Sstevel@tonic-gate if (ctx == NULL || (ctx->kc_flags & KCPC_CTX_LWPINHERIT) == 0)
13820Sstevel@tonic-gate return;
13830Sstevel@tonic-gate
13840Sstevel@tonic-gate rw_enter(&kcpc_cpuctx_lock, RW_READER);
13850Sstevel@tonic-gate if (ctx->kc_flags & KCPC_CTX_INVALID) {
13860Sstevel@tonic-gate rw_exit(&kcpc_cpuctx_lock);
13870Sstevel@tonic-gate return;
13880Sstevel@tonic-gate }
138911389SAlexander.Kolbasov@Sun.COM cctx = kcpc_ctx_alloc(KM_SLEEP);
13900Sstevel@tonic-gate kcpc_ctx_clone(ctx, cctx);
13910Sstevel@tonic-gate rw_exit(&kcpc_cpuctx_lock);
13920Sstevel@tonic-gate
13933732Sae112802 /*
13943732Sae112802 * Copy the parent context's kc_flags field, but don't overwrite
13953732Sae112802 * the child's in case it was modified during kcpc_ctx_clone.
13963732Sae112802 */
139711389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(cctx, ctx->kc_flags);
13980Sstevel@tonic-gate cctx->kc_thread = ct;
13990Sstevel@tonic-gate cctx->kc_cpuid = -1;
14000Sstevel@tonic-gate ct->t_cpc_set = cctx->kc_set;
14010Sstevel@tonic-gate ct->t_cpc_ctx = cctx;
14020Sstevel@tonic-gate
14030Sstevel@tonic-gate if (cctx->kc_flags & KCPC_CTX_SIGOVF) {
14040Sstevel@tonic-gate kcpc_set_t *ks = cctx->kc_set;
14050Sstevel@tonic-gate /*
14060Sstevel@tonic-gate * Our contract with the user requires us to immediately send an
14070Sstevel@tonic-gate * overflow signal to all children if we have the LWPINHERIT
14080Sstevel@tonic-gate * and SIGOVF flags set. In addition, all counters should be
14090Sstevel@tonic-gate * set to UINT64_MAX, and their pic's overflow flag turned on
14100Sstevel@tonic-gate * so that our trap() processing knows to send a signal.
14110Sstevel@tonic-gate */
141211389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_FREEZE);
14130Sstevel@tonic-gate for (i = 0; i < ks->ks_nreqs; i++) {
14140Sstevel@tonic-gate kcpc_request_t *kr = &ks->ks_req[i];
14150Sstevel@tonic-gate
14160Sstevel@tonic-gate if (kr->kr_flags & CPC_OVF_NOTIFY_EMT) {
14170Sstevel@tonic-gate *(kr->kr_data) = UINT64_MAX;
141811389SAlexander.Kolbasov@Sun.COM atomic_or_uint(&kr->kr_picp->kp_flags,
141911389SAlexander.Kolbasov@Sun.COM KCPC_PIC_OVERFLOWED);
14200Sstevel@tonic-gate }
14210Sstevel@tonic-gate }
14220Sstevel@tonic-gate ttolwp(ct)->lwp_pcb.pcb_flags |= CPC_OVERFLOW;
14230Sstevel@tonic-gate aston(ct);
14240Sstevel@tonic-gate }
14250Sstevel@tonic-gate
14260Sstevel@tonic-gate installctx(ct, cctx, kcpc_save, kcpc_restore,
14270Sstevel@tonic-gate NULL, kcpc_lwp_create, NULL, kcpc_free);
14280Sstevel@tonic-gate }
14290Sstevel@tonic-gate
14300Sstevel@tonic-gate /*
14310Sstevel@tonic-gate * Counter Stoppage Theory
14320Sstevel@tonic-gate *
14330Sstevel@tonic-gate * The counters may need to be stopped properly at the following occasions:
14340Sstevel@tonic-gate *
14350Sstevel@tonic-gate * 1) An LWP exits.
14360Sstevel@tonic-gate * 2) A thread exits.
14370Sstevel@tonic-gate * 3) An LWP performs an exec().
14380Sstevel@tonic-gate * 4) A bound set is unbound.
14390Sstevel@tonic-gate *
14400Sstevel@tonic-gate * In addition to stopping the counters, the CPC context (a kcpc_ctx_t) may need
14410Sstevel@tonic-gate * to be freed as well.
14420Sstevel@tonic-gate *
14430Sstevel@tonic-gate * Case 1: kcpc_passivate(), called via lwp_exit(), stops the counters. Later on
14440Sstevel@tonic-gate * when the thread is freed, kcpc_free(), called by freectx(), frees the
14450Sstevel@tonic-gate * context.
14460Sstevel@tonic-gate *
14470Sstevel@tonic-gate * Case 2: same as case 1 except kcpc_passivate is called from thread_exit().
14480Sstevel@tonic-gate *
14490Sstevel@tonic-gate * Case 3: kcpc_free(), called via freectx() via exec(), recognizes that it has
14500Sstevel@tonic-gate * been called from exec. It stops the counters _and_ frees the context.
14510Sstevel@tonic-gate *
14520Sstevel@tonic-gate * Case 4: kcpc_unbind() stops the hardware _and_ frees the context.
14530Sstevel@tonic-gate *
14540Sstevel@tonic-gate * CPU-bound counters are always stopped via kcpc_unbind().
14550Sstevel@tonic-gate */
14560Sstevel@tonic-gate
14570Sstevel@tonic-gate /*
14580Sstevel@tonic-gate * We're being called to delete the context; we ensure that all associated data
14590Sstevel@tonic-gate * structures are freed, and that the hardware is passivated if this is an exec.
14600Sstevel@tonic-gate */
14610Sstevel@tonic-gate
14620Sstevel@tonic-gate /*ARGSUSED*/
146311389SAlexander.Kolbasov@Sun.COM void
kcpc_free(kcpc_ctx_t * ctx,int isexec)14640Sstevel@tonic-gate kcpc_free(kcpc_ctx_t *ctx, int isexec)
14650Sstevel@tonic-gate {
14660Sstevel@tonic-gate int i;
14670Sstevel@tonic-gate kcpc_set_t *set = ctx->kc_set;
14680Sstevel@tonic-gate
14690Sstevel@tonic-gate ASSERT(set != NULL);
14700Sstevel@tonic-gate
14716275Strevtom /*
14726275Strevtom * Wait for kcpc_restore() to finish before we tear things down.
14736275Strevtom */
14746275Strevtom mutex_enter(&ctx->kc_lock);
14756275Strevtom while (ctx->kc_flags & KCPC_CTX_RESTORE)
14766275Strevtom cv_wait(&ctx->kc_condv, &ctx->kc_lock);
147711389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_INVALID);
14786275Strevtom mutex_exit(&ctx->kc_lock);
14790Sstevel@tonic-gate
14800Sstevel@tonic-gate if (isexec) {
14810Sstevel@tonic-gate /*
14820Sstevel@tonic-gate * This thread is execing, and after the exec it should not have
14830Sstevel@tonic-gate * any performance counter context. Stop the counters properly
14840Sstevel@tonic-gate * here so the system isn't surprised by an overflow interrupt
14850Sstevel@tonic-gate * later.
14860Sstevel@tonic-gate */
14870Sstevel@tonic-gate if (ctx->kc_cpuid != -1) {
14880Sstevel@tonic-gate cpu_t *cp;
14890Sstevel@tonic-gate /*
14900Sstevel@tonic-gate * CPU-bound context; stop the appropriate CPU's ctrs.
14910Sstevel@tonic-gate * Hold cpu_lock while examining the CPU to ensure it
14920Sstevel@tonic-gate * doesn't go away.
14930Sstevel@tonic-gate */
14940Sstevel@tonic-gate mutex_enter(&cpu_lock);
14950Sstevel@tonic-gate cp = cpu_get(ctx->kc_cpuid);
14960Sstevel@tonic-gate /*
14970Sstevel@tonic-gate * The CPU could have been DR'd out, so only stop the
14980Sstevel@tonic-gate * CPU and clear its context pointer if the CPU still
14990Sstevel@tonic-gate * exists.
15000Sstevel@tonic-gate */
15010Sstevel@tonic-gate if (cp != NULL) {
15020Sstevel@tonic-gate mutex_enter(&cp->cpu_cpc_ctxlock);
15030Sstevel@tonic-gate kcpc_stop_hw(ctx);
15040Sstevel@tonic-gate mutex_exit(&cp->cpu_cpc_ctxlock);
15050Sstevel@tonic-gate }
15060Sstevel@tonic-gate mutex_exit(&cpu_lock);
15070Sstevel@tonic-gate ASSERT(curthread->t_cpc_ctx == NULL);
15080Sstevel@tonic-gate } else {
150911389SAlexander.Kolbasov@Sun.COM int save_spl;
151011389SAlexander.Kolbasov@Sun.COM
15110Sstevel@tonic-gate /*
15120Sstevel@tonic-gate * Thread-bound context; stop _this_ CPU's counters.
15130Sstevel@tonic-gate */
15140Sstevel@tonic-gate kpreempt_disable();
151511389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall();
151611389SAlexander.Kolbasov@Sun.COM kcpc_unprogram(ctx, B_TRUE);
151711389SAlexander.Kolbasov@Sun.COM curthread->t_cpc_ctx = NULL;
151811389SAlexander.Kolbasov@Sun.COM splx(save_spl);
15190Sstevel@tonic-gate kpreempt_enable();
15200Sstevel@tonic-gate }
15210Sstevel@tonic-gate
15220Sstevel@tonic-gate /*
15230Sstevel@tonic-gate * Since we are being called from an exec and we know that
15240Sstevel@tonic-gate * exec is not permitted via the agent thread, we should clean
15250Sstevel@tonic-gate * up this thread's CPC state completely, and not leave dangling
15260Sstevel@tonic-gate * CPC pointers behind.
15270Sstevel@tonic-gate */
15280Sstevel@tonic-gate ASSERT(ctx->kc_thread == curthread);
15290Sstevel@tonic-gate curthread->t_cpc_set = NULL;
15300Sstevel@tonic-gate }
15310Sstevel@tonic-gate
15320Sstevel@tonic-gate /*
15330Sstevel@tonic-gate * Walk through each request in this context's set and free the PCBE's
15340Sstevel@tonic-gate * configuration if it exists.
15350Sstevel@tonic-gate */
15360Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++) {
15370Sstevel@tonic-gate if (set->ks_req[i].kr_config != NULL)
15380Sstevel@tonic-gate pcbe_ops->pcbe_free(set->ks_req[i].kr_config);
15390Sstevel@tonic-gate }
15400Sstevel@tonic-gate
15410Sstevel@tonic-gate kmem_free(set->ks_data, set->ks_nreqs * sizeof (uint64_t));
15420Sstevel@tonic-gate kcpc_ctx_free(ctx);
15430Sstevel@tonic-gate kcpc_free_set(set);
15440Sstevel@tonic-gate }
15450Sstevel@tonic-gate
15460Sstevel@tonic-gate /*
15470Sstevel@tonic-gate * Free the memory associated with a request set.
15480Sstevel@tonic-gate */
15490Sstevel@tonic-gate void
kcpc_free_set(kcpc_set_t * set)15500Sstevel@tonic-gate kcpc_free_set(kcpc_set_t *set)
15510Sstevel@tonic-gate {
15520Sstevel@tonic-gate int i;
15530Sstevel@tonic-gate kcpc_request_t *req;
15540Sstevel@tonic-gate
15550Sstevel@tonic-gate ASSERT(set->ks_req != NULL);
15560Sstevel@tonic-gate
15570Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++) {
15580Sstevel@tonic-gate req = &set->ks_req[i];
15590Sstevel@tonic-gate
15600Sstevel@tonic-gate if (req->kr_nattrs != 0) {
15610Sstevel@tonic-gate kmem_free(req->kr_attr,
15620Sstevel@tonic-gate req->kr_nattrs * sizeof (kcpc_attr_t));
15630Sstevel@tonic-gate }
15640Sstevel@tonic-gate }
15650Sstevel@tonic-gate
15660Sstevel@tonic-gate kmem_free(set->ks_req, sizeof (kcpc_request_t) * set->ks_nreqs);
15676275Strevtom cv_destroy(&set->ks_condv);
15686275Strevtom mutex_destroy(&set->ks_lock);
15690Sstevel@tonic-gate kmem_free(set, sizeof (kcpc_set_t));
15700Sstevel@tonic-gate }
15710Sstevel@tonic-gate
15720Sstevel@tonic-gate /*
15730Sstevel@tonic-gate * Grab every existing context and mark it as invalid.
15740Sstevel@tonic-gate */
15750Sstevel@tonic-gate void
kcpc_invalidate_all(void)15760Sstevel@tonic-gate kcpc_invalidate_all(void)
15770Sstevel@tonic-gate {
15780Sstevel@tonic-gate kcpc_ctx_t *ctx;
15790Sstevel@tonic-gate long hash;
15800Sstevel@tonic-gate
15810Sstevel@tonic-gate for (hash = 0; hash < CPC_HASH_BUCKETS; hash++) {
15820Sstevel@tonic-gate mutex_enter(&kcpc_ctx_llock[hash]);
15830Sstevel@tonic-gate for (ctx = kcpc_ctx_list[hash]; ctx; ctx = ctx->kc_next)
158411389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_INVALID);
15850Sstevel@tonic-gate mutex_exit(&kcpc_ctx_llock[hash]);
15860Sstevel@tonic-gate }
15870Sstevel@tonic-gate }
15880Sstevel@tonic-gate
15890Sstevel@tonic-gate /*
15903732Sae112802 * Interface for PCBEs to signal that an existing configuration has suddenly
15913732Sae112802 * become invalid.
15923732Sae112802 */
15933732Sae112802 void
kcpc_invalidate_config(void * token)15943732Sae112802 kcpc_invalidate_config(void *token)
15953732Sae112802 {
15963732Sae112802 kcpc_ctx_t *ctx = token;
15973732Sae112802
15983732Sae112802 ASSERT(ctx != NULL);
15993732Sae112802
160011389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_INVALID);
16013732Sae112802 }
16023732Sae112802
16033732Sae112802 /*
16040Sstevel@tonic-gate * Called from lwp_exit() and thread_exit()
16050Sstevel@tonic-gate */
16060Sstevel@tonic-gate void
kcpc_passivate(void)16070Sstevel@tonic-gate kcpc_passivate(void)
16080Sstevel@tonic-gate {
16090Sstevel@tonic-gate kcpc_ctx_t *ctx = curthread->t_cpc_ctx;
16100Sstevel@tonic-gate kcpc_set_t *set = curthread->t_cpc_set;
161111389SAlexander.Kolbasov@Sun.COM int save_spl;
16120Sstevel@tonic-gate
16130Sstevel@tonic-gate if (set == NULL)
16140Sstevel@tonic-gate return;
16150Sstevel@tonic-gate
16160Sstevel@tonic-gate if (ctx == NULL) {
16170Sstevel@tonic-gate /*
16180Sstevel@tonic-gate * This thread has a set but no context; it must be a CPU-bound
16190Sstevel@tonic-gate * set. The hardware will be stopped via kcpc_unbind() when the
16200Sstevel@tonic-gate * process exits and closes its file descriptors with
16210Sstevel@tonic-gate * kcpc_close(). Our only job here is to clean up this thread's
16220Sstevel@tonic-gate * state; the set will be freed with the unbind().
16230Sstevel@tonic-gate */
16240Sstevel@tonic-gate (void) kcpc_unbind(set);
16250Sstevel@tonic-gate /*
16260Sstevel@tonic-gate * Unbinding a set belonging to the current thread should clear
16270Sstevel@tonic-gate * its set pointer.
16280Sstevel@tonic-gate */
16290Sstevel@tonic-gate ASSERT(curthread->t_cpc_set == NULL);
16300Sstevel@tonic-gate return;
16310Sstevel@tonic-gate }
16320Sstevel@tonic-gate
163311389SAlexander.Kolbasov@Sun.COM kpreempt_disable();
163411389SAlexander.Kolbasov@Sun.COM save_spl = spl_xcall();
16350Sstevel@tonic-gate curthread->t_cpc_set = NULL;
16360Sstevel@tonic-gate
16370Sstevel@tonic-gate /*
16380Sstevel@tonic-gate * This thread/LWP is exiting but context switches will continue to
16390Sstevel@tonic-gate * happen for a bit as the exit proceeds. Kernel preemption must be
16400Sstevel@tonic-gate * disabled here to prevent a race between checking or setting the
16410Sstevel@tonic-gate * INVALID_STOPPED flag here and kcpc_restore() setting the flag during
16420Sstevel@tonic-gate * a context switch.
16430Sstevel@tonic-gate */
16440Sstevel@tonic-gate if ((ctx->kc_flags & KCPC_CTX_INVALID_STOPPED) == 0) {
164511389SAlexander.Kolbasov@Sun.COM kcpc_unprogram(ctx, B_TRUE);
164611389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx,
16470Sstevel@tonic-gate KCPC_CTX_INVALID | KCPC_CTX_INVALID_STOPPED);
16480Sstevel@tonic-gate }
164911389SAlexander.Kolbasov@Sun.COM
165011389SAlexander.Kolbasov@Sun.COM /*
165111389SAlexander.Kolbasov@Sun.COM * We're cleaning up after this thread; ensure there are no dangling
165211389SAlexander.Kolbasov@Sun.COM * CPC pointers left behind. The context and set will be freed by
165311389SAlexander.Kolbasov@Sun.COM * freectx().
165411389SAlexander.Kolbasov@Sun.COM */
165511389SAlexander.Kolbasov@Sun.COM curthread->t_cpc_ctx = NULL;
165611389SAlexander.Kolbasov@Sun.COM
165711389SAlexander.Kolbasov@Sun.COM splx(save_spl);
16580Sstevel@tonic-gate kpreempt_enable();
16590Sstevel@tonic-gate }
16600Sstevel@tonic-gate
16610Sstevel@tonic-gate /*
16620Sstevel@tonic-gate * Assign the requests in the given set to the PICs in the context.
16630Sstevel@tonic-gate * Returns 0 if successful, -1 on failure.
16640Sstevel@tonic-gate */
16650Sstevel@tonic-gate /*ARGSUSED*/
16668803SJonathan.Haslam@Sun.COM int
kcpc_assign_reqs(kcpc_set_t * set,kcpc_ctx_t * ctx)16670Sstevel@tonic-gate kcpc_assign_reqs(kcpc_set_t *set, kcpc_ctx_t *ctx)
16680Sstevel@tonic-gate {
16690Sstevel@tonic-gate int i;
16700Sstevel@tonic-gate int *picnum_save;
16710Sstevel@tonic-gate
16720Sstevel@tonic-gate ASSERT(set->ks_nreqs <= cpc_ncounters);
16730Sstevel@tonic-gate
16740Sstevel@tonic-gate /*
16750Sstevel@tonic-gate * Provide kcpc_tryassign() with scratch space to avoid doing an
16760Sstevel@tonic-gate * alloc/free with every invocation.
16770Sstevel@tonic-gate */
16780Sstevel@tonic-gate picnum_save = kmem_alloc(set->ks_nreqs * sizeof (int), KM_SLEEP);
16790Sstevel@tonic-gate /*
16800Sstevel@tonic-gate * kcpc_tryassign() blindly walks through each request in the set,
16810Sstevel@tonic-gate * seeing if a counter can count its event. If yes, it assigns that
16820Sstevel@tonic-gate * counter. However, that counter may have been the only capable counter
16830Sstevel@tonic-gate * for _another_ request's event. The solution is to try every possible
16840Sstevel@tonic-gate * request first. Note that this does not cover all solutions, as
16850Sstevel@tonic-gate * that would require all unique orderings of requests, an n^n operation
16860Sstevel@tonic-gate * which would be unacceptable for architectures with many counters.
16870Sstevel@tonic-gate */
16880Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++)
16890Sstevel@tonic-gate if (kcpc_tryassign(set, i, picnum_save) == 0)
16900Sstevel@tonic-gate break;
16910Sstevel@tonic-gate
16920Sstevel@tonic-gate kmem_free(picnum_save, set->ks_nreqs * sizeof (int));
16930Sstevel@tonic-gate if (i == set->ks_nreqs)
16940Sstevel@tonic-gate return (-1);
16950Sstevel@tonic-gate return (0);
16960Sstevel@tonic-gate }
16970Sstevel@tonic-gate
16980Sstevel@tonic-gate static int
kcpc_tryassign(kcpc_set_t * set,int starting_req,int * scratch)16990Sstevel@tonic-gate kcpc_tryassign(kcpc_set_t *set, int starting_req, int *scratch)
17000Sstevel@tonic-gate {
17010Sstevel@tonic-gate int i;
17020Sstevel@tonic-gate int j;
17030Sstevel@tonic-gate uint64_t bitmap = 0, resmap = 0;
17040Sstevel@tonic-gate uint64_t ctrmap;
17050Sstevel@tonic-gate
17060Sstevel@tonic-gate /*
17070Sstevel@tonic-gate * We are attempting to assign the reqs to pics, but we may fail. If we
17080Sstevel@tonic-gate * fail, we need to restore the state of the requests to what it was
17090Sstevel@tonic-gate * when we found it, as some reqs may have been explicitly assigned to
17100Sstevel@tonic-gate * a specific PIC beforehand. We do this by snapshotting the assignments
17110Sstevel@tonic-gate * now and restoring from it later if we fail.
17120Sstevel@tonic-gate *
17130Sstevel@tonic-gate * Also we note here which counters have already been claimed by
17140Sstevel@tonic-gate * requests with explicit counter assignments.
17150Sstevel@tonic-gate */
17160Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++) {
17170Sstevel@tonic-gate scratch[i] = set->ks_req[i].kr_picnum;
17180Sstevel@tonic-gate if (set->ks_req[i].kr_picnum != -1)
17190Sstevel@tonic-gate resmap |= (1 << set->ks_req[i].kr_picnum);
17200Sstevel@tonic-gate }
17210Sstevel@tonic-gate
17220Sstevel@tonic-gate /*
17230Sstevel@tonic-gate * Walk through requests assigning them to the first PIC that is
17240Sstevel@tonic-gate * capable.
17250Sstevel@tonic-gate */
17260Sstevel@tonic-gate i = starting_req;
17270Sstevel@tonic-gate do {
17280Sstevel@tonic-gate if (set->ks_req[i].kr_picnum != -1) {
17290Sstevel@tonic-gate ASSERT((bitmap & (1 << set->ks_req[i].kr_picnum)) == 0);
17300Sstevel@tonic-gate bitmap |= (1 << set->ks_req[i].kr_picnum);
17310Sstevel@tonic-gate if (++i == set->ks_nreqs)
17320Sstevel@tonic-gate i = 0;
17330Sstevel@tonic-gate continue;
17340Sstevel@tonic-gate }
17350Sstevel@tonic-gate
17360Sstevel@tonic-gate ctrmap = pcbe_ops->pcbe_event_coverage(set->ks_req[i].kr_event);
17370Sstevel@tonic-gate for (j = 0; j < cpc_ncounters; j++) {
17380Sstevel@tonic-gate if (ctrmap & (1 << j) && (bitmap & (1 << j)) == 0 &&
17390Sstevel@tonic-gate (resmap & (1 << j)) == 0) {
17400Sstevel@tonic-gate /*
17410Sstevel@tonic-gate * We can assign this counter because:
17420Sstevel@tonic-gate *
17430Sstevel@tonic-gate * 1. It can count the event (ctrmap)
17440Sstevel@tonic-gate * 2. It hasn't been assigned yet (bitmap)
17450Sstevel@tonic-gate * 3. It wasn't reserved by a request (resmap)
17460Sstevel@tonic-gate */
17470Sstevel@tonic-gate bitmap |= (1 << j);
17480Sstevel@tonic-gate break;
17490Sstevel@tonic-gate }
17500Sstevel@tonic-gate }
17510Sstevel@tonic-gate if (j == cpc_ncounters) {
17520Sstevel@tonic-gate for (i = 0; i < set->ks_nreqs; i++)
17530Sstevel@tonic-gate set->ks_req[i].kr_picnum = scratch[i];
17540Sstevel@tonic-gate return (-1);
17550Sstevel@tonic-gate }
17560Sstevel@tonic-gate set->ks_req[i].kr_picnum = j;
17570Sstevel@tonic-gate
17580Sstevel@tonic-gate if (++i == set->ks_nreqs)
17590Sstevel@tonic-gate i = 0;
17600Sstevel@tonic-gate } while (i != starting_req);
17610Sstevel@tonic-gate
17620Sstevel@tonic-gate return (0);
17630Sstevel@tonic-gate }
17640Sstevel@tonic-gate
17650Sstevel@tonic-gate kcpc_set_t *
kcpc_dup_set(kcpc_set_t * set)17660Sstevel@tonic-gate kcpc_dup_set(kcpc_set_t *set)
17670Sstevel@tonic-gate {
17680Sstevel@tonic-gate kcpc_set_t *new;
17690Sstevel@tonic-gate int i;
17700Sstevel@tonic-gate int j;
17710Sstevel@tonic-gate
17726275Strevtom new = kmem_zalloc(sizeof (*new), KM_SLEEP);
17736275Strevtom new->ks_state &= ~KCPC_SET_BOUND;
17740Sstevel@tonic-gate new->ks_flags = set->ks_flags;
17750Sstevel@tonic-gate new->ks_nreqs = set->ks_nreqs;
17760Sstevel@tonic-gate new->ks_req = kmem_alloc(set->ks_nreqs * sizeof (kcpc_request_t),
17770Sstevel@tonic-gate KM_SLEEP);
17780Sstevel@tonic-gate new->ks_data = NULL;
17790Sstevel@tonic-gate new->ks_ctx = NULL;
17800Sstevel@tonic-gate
17810Sstevel@tonic-gate for (i = 0; i < new->ks_nreqs; i++) {
17820Sstevel@tonic-gate new->ks_req[i].kr_config = NULL;
17830Sstevel@tonic-gate new->ks_req[i].kr_index = set->ks_req[i].kr_index;
17840Sstevel@tonic-gate new->ks_req[i].kr_picnum = set->ks_req[i].kr_picnum;
17850Sstevel@tonic-gate new->ks_req[i].kr_picp = NULL;
17860Sstevel@tonic-gate new->ks_req[i].kr_data = NULL;
17870Sstevel@tonic-gate (void) strncpy(new->ks_req[i].kr_event, set->ks_req[i].kr_event,
17880Sstevel@tonic-gate CPC_MAX_EVENT_LEN);
17890Sstevel@tonic-gate new->ks_req[i].kr_preset = set->ks_req[i].kr_preset;
17900Sstevel@tonic-gate new->ks_req[i].kr_flags = set->ks_req[i].kr_flags;
17910Sstevel@tonic-gate new->ks_req[i].kr_nattrs = set->ks_req[i].kr_nattrs;
17920Sstevel@tonic-gate new->ks_req[i].kr_attr = kmem_alloc(new->ks_req[i].kr_nattrs *
17930Sstevel@tonic-gate sizeof (kcpc_attr_t), KM_SLEEP);
17940Sstevel@tonic-gate for (j = 0; j < new->ks_req[i].kr_nattrs; j++) {
17950Sstevel@tonic-gate new->ks_req[i].kr_attr[j].ka_val =
17960Sstevel@tonic-gate set->ks_req[i].kr_attr[j].ka_val;
17970Sstevel@tonic-gate (void) strncpy(new->ks_req[i].kr_attr[j].ka_name,
17980Sstevel@tonic-gate set->ks_req[i].kr_attr[j].ka_name,
17990Sstevel@tonic-gate CPC_MAX_ATTR_LEN);
18000Sstevel@tonic-gate }
18010Sstevel@tonic-gate }
18020Sstevel@tonic-gate
18030Sstevel@tonic-gate return (new);
18040Sstevel@tonic-gate }
18050Sstevel@tonic-gate
18060Sstevel@tonic-gate int
kcpc_allow_nonpriv(void * token)18070Sstevel@tonic-gate kcpc_allow_nonpriv(void *token)
18080Sstevel@tonic-gate {
18090Sstevel@tonic-gate return (((kcpc_ctx_t *)token)->kc_flags & KCPC_CTX_NONPRIV);
18100Sstevel@tonic-gate }
18110Sstevel@tonic-gate
18120Sstevel@tonic-gate void
kcpc_invalidate(kthread_t * t)18130Sstevel@tonic-gate kcpc_invalidate(kthread_t *t)
18140Sstevel@tonic-gate {
18150Sstevel@tonic-gate kcpc_ctx_t *ctx = t->t_cpc_ctx;
18160Sstevel@tonic-gate
18170Sstevel@tonic-gate if (ctx != NULL)
181811389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_INVALID);
18190Sstevel@tonic-gate }
18200Sstevel@tonic-gate
18210Sstevel@tonic-gate /*
18220Sstevel@tonic-gate * Given a PCBE ID, attempt to load a matching PCBE module. The strings given
18230Sstevel@tonic-gate * are used to construct PCBE names, starting with the most specific,
18240Sstevel@tonic-gate * "pcbe.first.second.third.fourth" and ending with the least specific,
18250Sstevel@tonic-gate * "pcbe.first".
18260Sstevel@tonic-gate *
18270Sstevel@tonic-gate * Returns 0 if a PCBE was successfully loaded and -1 upon error.
18280Sstevel@tonic-gate */
18290Sstevel@tonic-gate int
kcpc_pcbe_tryload(const char * prefix,uint_t first,uint_t second,uint_t third)18300Sstevel@tonic-gate kcpc_pcbe_tryload(const char *prefix, uint_t first, uint_t second, uint_t third)
18310Sstevel@tonic-gate {
18321414Scindi uint_t s[3];
18330Sstevel@tonic-gate
18341414Scindi s[0] = first;
18351414Scindi s[1] = second;
18361414Scindi s[2] = third;
18370Sstevel@tonic-gate
18381414Scindi return (modload_qualified("pcbe",
18395254Sgavinm "pcbe", prefix, ".", s, 3, NULL) < 0 ? -1 : 0);
18400Sstevel@tonic-gate }
18418803SJonathan.Haslam@Sun.COM
184211389SAlexander.Kolbasov@Sun.COM /*
184311389SAlexander.Kolbasov@Sun.COM * Create one or more CPC context for given CPU with specified counter event
184411389SAlexander.Kolbasov@Sun.COM * requests
184511389SAlexander.Kolbasov@Sun.COM *
184611389SAlexander.Kolbasov@Sun.COM * If number of requested counter events is less than or equal number of
184711389SAlexander.Kolbasov@Sun.COM * hardware counters on a CPU and can all be assigned to the counters on a CPU
184811389SAlexander.Kolbasov@Sun.COM * at the same time, then make one CPC context.
184911389SAlexander.Kolbasov@Sun.COM *
185011389SAlexander.Kolbasov@Sun.COM * Otherwise, multiple CPC contexts are created to allow multiplexing more
185111389SAlexander.Kolbasov@Sun.COM * counter events than existing counters onto the counters by iterating through
185211389SAlexander.Kolbasov@Sun.COM * all of the CPC contexts, programming the counters with each CPC context one
185311389SAlexander.Kolbasov@Sun.COM * at a time and measuring the resulting counter values. Each of the resulting
185411389SAlexander.Kolbasov@Sun.COM * CPC contexts contains some number of requested counter events less than or
185511389SAlexander.Kolbasov@Sun.COM * equal the number of counters on a CPU depending on whether all the counter
185611389SAlexander.Kolbasov@Sun.COM * events can be programmed on all the counters at the same time or not.
185711389SAlexander.Kolbasov@Sun.COM *
185811389SAlexander.Kolbasov@Sun.COM * Flags to kmem_{,z}alloc() are passed in as an argument to allow specifying
185911389SAlexander.Kolbasov@Sun.COM * whether memory allocation should be non-blocking or not. The code will try
186011389SAlexander.Kolbasov@Sun.COM * to allocate *whole* CPC contexts if possible. If there is any memory
186111389SAlexander.Kolbasov@Sun.COM * allocation failure during the allocations needed for a given CPC context, it
186211389SAlexander.Kolbasov@Sun.COM * will skip allocating that CPC context because it cannot allocate the whole
186311389SAlexander.Kolbasov@Sun.COM * thing. Thus, the only time that it will end up allocating none (ie. no CPC
186411389SAlexander.Kolbasov@Sun.COM * contexts whatsoever) is when it cannot even allocate *one* whole CPC context
186511389SAlexander.Kolbasov@Sun.COM * without a memory allocation failure occurring.
186611389SAlexander.Kolbasov@Sun.COM */
186711389SAlexander.Kolbasov@Sun.COM int
kcpc_cpu_ctx_create(cpu_t * cp,kcpc_request_list_t * req_list,int kmem_flags,kcpc_ctx_t *** ctx_ptr_array,size_t * ctx_ptr_array_sz)186811389SAlexander.Kolbasov@Sun.COM kcpc_cpu_ctx_create(cpu_t *cp, kcpc_request_list_t *req_list, int kmem_flags,
186911389SAlexander.Kolbasov@Sun.COM kcpc_ctx_t ***ctx_ptr_array, size_t *ctx_ptr_array_sz)
187011389SAlexander.Kolbasov@Sun.COM {
187111389SAlexander.Kolbasov@Sun.COM kcpc_ctx_t **ctx_ptrs;
187211389SAlexander.Kolbasov@Sun.COM int nctx;
187311389SAlexander.Kolbasov@Sun.COM int nctx_ptrs;
187411389SAlexander.Kolbasov@Sun.COM int nreqs;
187511389SAlexander.Kolbasov@Sun.COM kcpc_request_t *reqs;
187611389SAlexander.Kolbasov@Sun.COM
187711389SAlexander.Kolbasov@Sun.COM if (cp == NULL || ctx_ptr_array == NULL || ctx_ptr_array_sz == NULL ||
187811389SAlexander.Kolbasov@Sun.COM req_list == NULL || req_list->krl_cnt < 1)
187911389SAlexander.Kolbasov@Sun.COM return (-1);
188011389SAlexander.Kolbasov@Sun.COM
188111389SAlexander.Kolbasov@Sun.COM /*
188211389SAlexander.Kolbasov@Sun.COM * Allocate number of sets assuming that each set contains one and only
188311389SAlexander.Kolbasov@Sun.COM * one counter event request for each counter on a CPU
188411389SAlexander.Kolbasov@Sun.COM */
188511389SAlexander.Kolbasov@Sun.COM nreqs = req_list->krl_cnt;
188611389SAlexander.Kolbasov@Sun.COM nctx_ptrs = (nreqs + cpc_ncounters - 1) / cpc_ncounters;
188711389SAlexander.Kolbasov@Sun.COM ctx_ptrs = kmem_zalloc(nctx_ptrs * sizeof (kcpc_ctx_t *), kmem_flags);
188811389SAlexander.Kolbasov@Sun.COM if (ctx_ptrs == NULL)
188911389SAlexander.Kolbasov@Sun.COM return (-2);
189011389SAlexander.Kolbasov@Sun.COM
189111389SAlexander.Kolbasov@Sun.COM /*
189211389SAlexander.Kolbasov@Sun.COM * Fill in sets of requests
189311389SAlexander.Kolbasov@Sun.COM */
189411389SAlexander.Kolbasov@Sun.COM nctx = 0;
189511389SAlexander.Kolbasov@Sun.COM reqs = req_list->krl_list;
189611389SAlexander.Kolbasov@Sun.COM while (nreqs > 0) {
189711389SAlexander.Kolbasov@Sun.COM kcpc_ctx_t *ctx;
189811389SAlexander.Kolbasov@Sun.COM kcpc_set_t *set;
189911389SAlexander.Kolbasov@Sun.COM int subcode;
190011389SAlexander.Kolbasov@Sun.COM
190111389SAlexander.Kolbasov@Sun.COM /*
190211389SAlexander.Kolbasov@Sun.COM * Allocate CPC context and set for requested counter events
190311389SAlexander.Kolbasov@Sun.COM */
190411389SAlexander.Kolbasov@Sun.COM ctx = kcpc_ctx_alloc(kmem_flags);
190511389SAlexander.Kolbasov@Sun.COM set = kcpc_set_create(reqs, nreqs, 0, kmem_flags);
190611389SAlexander.Kolbasov@Sun.COM if (set == NULL) {
190711389SAlexander.Kolbasov@Sun.COM kcpc_ctx_free(ctx);
190811389SAlexander.Kolbasov@Sun.COM break;
190911389SAlexander.Kolbasov@Sun.COM }
191011389SAlexander.Kolbasov@Sun.COM
191111389SAlexander.Kolbasov@Sun.COM /*
191211389SAlexander.Kolbasov@Sun.COM * Determine assignment of requested counter events to specific
191311389SAlexander.Kolbasov@Sun.COM * counters
191411389SAlexander.Kolbasov@Sun.COM */
191511389SAlexander.Kolbasov@Sun.COM if (kcpc_assign_reqs(set, ctx) != 0) {
191611389SAlexander.Kolbasov@Sun.COM /*
191711389SAlexander.Kolbasov@Sun.COM * May not be able to assign requested counter events
191811389SAlexander.Kolbasov@Sun.COM * to all counters since all counters may not be able
191911389SAlexander.Kolbasov@Sun.COM * to do all events, so only do one counter event in
192011389SAlexander.Kolbasov@Sun.COM * set of counter requests when this happens since at
192111389SAlexander.Kolbasov@Sun.COM * least one of the counters must be able to do the
192211389SAlexander.Kolbasov@Sun.COM * event.
192311389SAlexander.Kolbasov@Sun.COM */
192411389SAlexander.Kolbasov@Sun.COM kcpc_free_set(set);
192511389SAlexander.Kolbasov@Sun.COM set = kcpc_set_create(reqs, 1, 0, kmem_flags);
192611389SAlexander.Kolbasov@Sun.COM if (set == NULL) {
192711389SAlexander.Kolbasov@Sun.COM kcpc_ctx_free(ctx);
192811389SAlexander.Kolbasov@Sun.COM break;
192911389SAlexander.Kolbasov@Sun.COM }
193011389SAlexander.Kolbasov@Sun.COM if (kcpc_assign_reqs(set, ctx) != 0) {
193111389SAlexander.Kolbasov@Sun.COM #ifdef DEBUG
193211389SAlexander.Kolbasov@Sun.COM cmn_err(CE_NOTE, "!kcpc_cpu_ctx_create: can't "
193311389SAlexander.Kolbasov@Sun.COM "assign counter event %s!\n",
193411389SAlexander.Kolbasov@Sun.COM set->ks_req->kr_event);
193511389SAlexander.Kolbasov@Sun.COM #endif
193611389SAlexander.Kolbasov@Sun.COM kcpc_free_set(set);
193711389SAlexander.Kolbasov@Sun.COM kcpc_ctx_free(ctx);
193811389SAlexander.Kolbasov@Sun.COM reqs++;
193911389SAlexander.Kolbasov@Sun.COM nreqs--;
194011389SAlexander.Kolbasov@Sun.COM continue;
194111389SAlexander.Kolbasov@Sun.COM }
194211389SAlexander.Kolbasov@Sun.COM }
194311389SAlexander.Kolbasov@Sun.COM
194411389SAlexander.Kolbasov@Sun.COM /*
194511389SAlexander.Kolbasov@Sun.COM * Allocate memory needed to hold requested counter event data
194611389SAlexander.Kolbasov@Sun.COM */
194711389SAlexander.Kolbasov@Sun.COM set->ks_data = kmem_zalloc(set->ks_nreqs * sizeof (uint64_t),
194811389SAlexander.Kolbasov@Sun.COM kmem_flags);
194911389SAlexander.Kolbasov@Sun.COM if (set->ks_data == NULL) {
195011389SAlexander.Kolbasov@Sun.COM kcpc_free_set(set);
195111389SAlexander.Kolbasov@Sun.COM kcpc_ctx_free(ctx);
195211389SAlexander.Kolbasov@Sun.COM break;
195311389SAlexander.Kolbasov@Sun.COM }
195411389SAlexander.Kolbasov@Sun.COM
195511389SAlexander.Kolbasov@Sun.COM /*
195611389SAlexander.Kolbasov@Sun.COM * Configure requested counter events
195711389SAlexander.Kolbasov@Sun.COM */
195811389SAlexander.Kolbasov@Sun.COM if (kcpc_configure_reqs(ctx, set, &subcode) != 0) {
195911389SAlexander.Kolbasov@Sun.COM #ifdef DEBUG
196011389SAlexander.Kolbasov@Sun.COM cmn_err(CE_NOTE,
196111389SAlexander.Kolbasov@Sun.COM "!kcpc_cpu_ctx_create: can't configure "
196211389SAlexander.Kolbasov@Sun.COM "set of counter event requests!\n");
196311389SAlexander.Kolbasov@Sun.COM #endif
196411389SAlexander.Kolbasov@Sun.COM reqs += set->ks_nreqs;
196511389SAlexander.Kolbasov@Sun.COM nreqs -= set->ks_nreqs;
196611389SAlexander.Kolbasov@Sun.COM kmem_free(set->ks_data,
196711389SAlexander.Kolbasov@Sun.COM set->ks_nreqs * sizeof (uint64_t));
196811389SAlexander.Kolbasov@Sun.COM kcpc_free_set(set);
196911389SAlexander.Kolbasov@Sun.COM kcpc_ctx_free(ctx);
197011389SAlexander.Kolbasov@Sun.COM continue;
197111389SAlexander.Kolbasov@Sun.COM }
197211389SAlexander.Kolbasov@Sun.COM
197311389SAlexander.Kolbasov@Sun.COM /*
197411389SAlexander.Kolbasov@Sun.COM * Point set of counter event requests at this context and fill
197511389SAlexander.Kolbasov@Sun.COM * in CPC context
197611389SAlexander.Kolbasov@Sun.COM */
197711389SAlexander.Kolbasov@Sun.COM set->ks_ctx = ctx;
197811389SAlexander.Kolbasov@Sun.COM ctx->kc_set = set;
197911389SAlexander.Kolbasov@Sun.COM ctx->kc_cpuid = cp->cpu_id;
198011389SAlexander.Kolbasov@Sun.COM ctx->kc_thread = curthread;
198111389SAlexander.Kolbasov@Sun.COM
198211389SAlexander.Kolbasov@Sun.COM ctx_ptrs[nctx] = ctx;
198311389SAlexander.Kolbasov@Sun.COM
198411389SAlexander.Kolbasov@Sun.COM /*
198511389SAlexander.Kolbasov@Sun.COM * Update requests and how many are left to be assigned to sets
198611389SAlexander.Kolbasov@Sun.COM */
198711389SAlexander.Kolbasov@Sun.COM reqs += set->ks_nreqs;
198811389SAlexander.Kolbasov@Sun.COM nreqs -= set->ks_nreqs;
198911389SAlexander.Kolbasov@Sun.COM
199011389SAlexander.Kolbasov@Sun.COM /*
199111389SAlexander.Kolbasov@Sun.COM * Increment number of CPC contexts and allocate bigger array
199211389SAlexander.Kolbasov@Sun.COM * for context pointers as needed
199311389SAlexander.Kolbasov@Sun.COM */
199411389SAlexander.Kolbasov@Sun.COM nctx++;
199511389SAlexander.Kolbasov@Sun.COM if (nctx >= nctx_ptrs) {
199611389SAlexander.Kolbasov@Sun.COM kcpc_ctx_t **new;
199711389SAlexander.Kolbasov@Sun.COM int new_cnt;
199811389SAlexander.Kolbasov@Sun.COM
199911389SAlexander.Kolbasov@Sun.COM /*
200011389SAlexander.Kolbasov@Sun.COM * Allocate more CPC contexts based on how many
200111389SAlexander.Kolbasov@Sun.COM * contexts allocated so far and how many counter
200211389SAlexander.Kolbasov@Sun.COM * requests left to assign
200311389SAlexander.Kolbasov@Sun.COM */
200411389SAlexander.Kolbasov@Sun.COM new_cnt = nctx_ptrs +
200511389SAlexander.Kolbasov@Sun.COM ((nreqs + cpc_ncounters - 1) / cpc_ncounters);
200611389SAlexander.Kolbasov@Sun.COM new = kmem_zalloc(new_cnt * sizeof (kcpc_ctx_t *),
200711389SAlexander.Kolbasov@Sun.COM kmem_flags);
200811389SAlexander.Kolbasov@Sun.COM if (new == NULL)
200911389SAlexander.Kolbasov@Sun.COM break;
201011389SAlexander.Kolbasov@Sun.COM
201111389SAlexander.Kolbasov@Sun.COM /*
201211389SAlexander.Kolbasov@Sun.COM * Copy contents of old sets into new ones
201311389SAlexander.Kolbasov@Sun.COM */
201411389SAlexander.Kolbasov@Sun.COM bcopy(ctx_ptrs, new,
201511389SAlexander.Kolbasov@Sun.COM nctx_ptrs * sizeof (kcpc_ctx_t *));
201611389SAlexander.Kolbasov@Sun.COM
201711389SAlexander.Kolbasov@Sun.COM /*
201811389SAlexander.Kolbasov@Sun.COM * Free old array of context pointers and use newly
201911389SAlexander.Kolbasov@Sun.COM * allocated one instead now
202011389SAlexander.Kolbasov@Sun.COM */
202111389SAlexander.Kolbasov@Sun.COM kmem_free(ctx_ptrs, nctx_ptrs * sizeof (kcpc_ctx_t *));
202211389SAlexander.Kolbasov@Sun.COM ctx_ptrs = new;
202311389SAlexander.Kolbasov@Sun.COM nctx_ptrs = new_cnt;
202411389SAlexander.Kolbasov@Sun.COM }
202511389SAlexander.Kolbasov@Sun.COM }
202611389SAlexander.Kolbasov@Sun.COM
202711389SAlexander.Kolbasov@Sun.COM /*
202811389SAlexander.Kolbasov@Sun.COM * Return NULL if no CPC contexts filled in
202911389SAlexander.Kolbasov@Sun.COM */
203011389SAlexander.Kolbasov@Sun.COM if (nctx == 0) {
203111389SAlexander.Kolbasov@Sun.COM kmem_free(ctx_ptrs, nctx_ptrs * sizeof (kcpc_ctx_t *));
203211389SAlexander.Kolbasov@Sun.COM *ctx_ptr_array = NULL;
203311389SAlexander.Kolbasov@Sun.COM *ctx_ptr_array_sz = 0;
203411389SAlexander.Kolbasov@Sun.COM return (-2);
203511389SAlexander.Kolbasov@Sun.COM }
203611389SAlexander.Kolbasov@Sun.COM
203711389SAlexander.Kolbasov@Sun.COM *ctx_ptr_array = ctx_ptrs;
203811389SAlexander.Kolbasov@Sun.COM *ctx_ptr_array_sz = nctx_ptrs * sizeof (kcpc_ctx_t *);
203911389SAlexander.Kolbasov@Sun.COM return (nctx);
204011389SAlexander.Kolbasov@Sun.COM }
204111389SAlexander.Kolbasov@Sun.COM
204211389SAlexander.Kolbasov@Sun.COM /*
204311389SAlexander.Kolbasov@Sun.COM * Return whether PCBE supports given counter event
204411389SAlexander.Kolbasov@Sun.COM */
204511389SAlexander.Kolbasov@Sun.COM boolean_t
kcpc_event_supported(char * event)204611389SAlexander.Kolbasov@Sun.COM kcpc_event_supported(char *event)
204711389SAlexander.Kolbasov@Sun.COM {
204811389SAlexander.Kolbasov@Sun.COM if (pcbe_ops == NULL || pcbe_ops->pcbe_event_coverage(event) == 0)
204911389SAlexander.Kolbasov@Sun.COM return (B_FALSE);
205011389SAlexander.Kolbasov@Sun.COM
205111389SAlexander.Kolbasov@Sun.COM return (B_TRUE);
205211389SAlexander.Kolbasov@Sun.COM }
205311389SAlexander.Kolbasov@Sun.COM
205411389SAlexander.Kolbasov@Sun.COM /*
205511389SAlexander.Kolbasov@Sun.COM * Program counters on current CPU with given CPC context
205611389SAlexander.Kolbasov@Sun.COM *
205711389SAlexander.Kolbasov@Sun.COM * If kernel is interposing on counters to measure hardware capacity and
205811389SAlexander.Kolbasov@Sun.COM * utilization, then unprogram counters for kernel *before* programming them
205911389SAlexander.Kolbasov@Sun.COM * with specified CPC context.
206011389SAlexander.Kolbasov@Sun.COM *
206111389SAlexander.Kolbasov@Sun.COM * kcpc_{program,unprogram}() may be called either directly by a thread running
206211389SAlexander.Kolbasov@Sun.COM * on the target CPU or from a cross-call from another CPU. To protect
206311389SAlexander.Kolbasov@Sun.COM * programming and unprogramming from being interrupted by cross-calls, callers
206411389SAlexander.Kolbasov@Sun.COM * who execute kcpc_{program,unprogram} should raise PIL to the level used by
206511389SAlexander.Kolbasov@Sun.COM * cross-calls.
206611389SAlexander.Kolbasov@Sun.COM */
206711389SAlexander.Kolbasov@Sun.COM void
kcpc_program(kcpc_ctx_t * ctx,boolean_t for_thread,boolean_t cu_interpose)206811389SAlexander.Kolbasov@Sun.COM kcpc_program(kcpc_ctx_t *ctx, boolean_t for_thread, boolean_t cu_interpose)
206911389SAlexander.Kolbasov@Sun.COM {
207011389SAlexander.Kolbasov@Sun.COM int error;
207111389SAlexander.Kolbasov@Sun.COM
207211389SAlexander.Kolbasov@Sun.COM ASSERT(IS_HIPIL());
207311389SAlexander.Kolbasov@Sun.COM
207411389SAlexander.Kolbasov@Sun.COM /*
207511389SAlexander.Kolbasov@Sun.COM * CPC context shouldn't be NULL, its CPU field should specify current
207611389SAlexander.Kolbasov@Sun.COM * CPU or be -1 to specify any CPU when the context is bound to a
207711389SAlexander.Kolbasov@Sun.COM * thread, and preemption should be disabled
207811389SAlexander.Kolbasov@Sun.COM */
207911389SAlexander.Kolbasov@Sun.COM ASSERT(ctx != NULL && (ctx->kc_cpuid == CPU->cpu_id ||
208011389SAlexander.Kolbasov@Sun.COM ctx->kc_cpuid == -1) && curthread->t_preempt > 0);
208111389SAlexander.Kolbasov@Sun.COM if (ctx == NULL || (ctx->kc_cpuid != CPU->cpu_id &&
208211389SAlexander.Kolbasov@Sun.COM ctx->kc_cpuid != -1) || curthread->t_preempt < 1)
208311389SAlexander.Kolbasov@Sun.COM return;
208411389SAlexander.Kolbasov@Sun.COM
208511389SAlexander.Kolbasov@Sun.COM /*
208611389SAlexander.Kolbasov@Sun.COM * Unprogram counters for kernel measuring hardware capacity and
208711389SAlexander.Kolbasov@Sun.COM * utilization
208811389SAlexander.Kolbasov@Sun.COM */
208911389SAlexander.Kolbasov@Sun.COM if (cu_interpose == B_TRUE) {
209011389SAlexander.Kolbasov@Sun.COM cu_cpc_unprogram(CPU, &error);
209111389SAlexander.Kolbasov@Sun.COM } else {
209211389SAlexander.Kolbasov@Sun.COM kcpc_set_t *set = ctx->kc_set;
209311389SAlexander.Kolbasov@Sun.COM int i;
209411389SAlexander.Kolbasov@Sun.COM
209511389SAlexander.Kolbasov@Sun.COM ASSERT(set != NULL);
209611389SAlexander.Kolbasov@Sun.COM
209711389SAlexander.Kolbasov@Sun.COM /*
209811389SAlexander.Kolbasov@Sun.COM * Since cu_interpose is false, we are programming CU context.
209911389SAlexander.Kolbasov@Sun.COM * In general, PCBE can continue from the state saved in the
210011389SAlexander.Kolbasov@Sun.COM * set, but it is not very reliable, so we start again from the
210111389SAlexander.Kolbasov@Sun.COM * preset value.
210211389SAlexander.Kolbasov@Sun.COM */
210311389SAlexander.Kolbasov@Sun.COM for (i = 0; i < set->ks_nreqs; i++) {
210411389SAlexander.Kolbasov@Sun.COM /*
210511389SAlexander.Kolbasov@Sun.COM * Reset the virtual counter value to the preset value.
210611389SAlexander.Kolbasov@Sun.COM */
210711389SAlexander.Kolbasov@Sun.COM *(set->ks_req[i].kr_data) = set->ks_req[i].kr_preset;
210811389SAlexander.Kolbasov@Sun.COM
210911389SAlexander.Kolbasov@Sun.COM /*
211011389SAlexander.Kolbasov@Sun.COM * Reset PCBE to the preset value.
211111389SAlexander.Kolbasov@Sun.COM */
211211389SAlexander.Kolbasov@Sun.COM pcbe_ops->pcbe_configure(0, NULL,
211311389SAlexander.Kolbasov@Sun.COM set->ks_req[i].kr_preset,
211411389SAlexander.Kolbasov@Sun.COM 0, 0, NULL, &set->ks_req[i].kr_config, NULL);
211511389SAlexander.Kolbasov@Sun.COM }
211611389SAlexander.Kolbasov@Sun.COM }
211711389SAlexander.Kolbasov@Sun.COM
211811389SAlexander.Kolbasov@Sun.COM /*
211911389SAlexander.Kolbasov@Sun.COM * Program counters with specified CPC context
212011389SAlexander.Kolbasov@Sun.COM */
212111389SAlexander.Kolbasov@Sun.COM ctx->kc_rawtick = KCPC_GET_TICK();
212211389SAlexander.Kolbasov@Sun.COM pcbe_ops->pcbe_program(ctx);
212311389SAlexander.Kolbasov@Sun.COM
212411389SAlexander.Kolbasov@Sun.COM /*
212511389SAlexander.Kolbasov@Sun.COM * Denote that counters programmed for thread or CPU CPC context
212611389SAlexander.Kolbasov@Sun.COM * differently
212711389SAlexander.Kolbasov@Sun.COM */
212811389SAlexander.Kolbasov@Sun.COM if (for_thread == B_TRUE)
212911389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_CLR(ctx, KCPC_CTX_FREEZE);
213011389SAlexander.Kolbasov@Sun.COM else
213111389SAlexander.Kolbasov@Sun.COM CPU->cpu_cpc_ctx = ctx;
213211389SAlexander.Kolbasov@Sun.COM }
213311389SAlexander.Kolbasov@Sun.COM
213411389SAlexander.Kolbasov@Sun.COM /*
213511389SAlexander.Kolbasov@Sun.COM * Unprogram counters with given CPC context on current CPU
213611389SAlexander.Kolbasov@Sun.COM *
213711389SAlexander.Kolbasov@Sun.COM * If kernel is interposing on counters to measure hardware capacity and
213811389SAlexander.Kolbasov@Sun.COM * utilization, then program counters for the kernel capacity and utilization
213911389SAlexander.Kolbasov@Sun.COM * *after* unprogramming them for given CPC context.
214011389SAlexander.Kolbasov@Sun.COM *
214111389SAlexander.Kolbasov@Sun.COM * See the comment for kcpc_program regarding the synchronization with
214211389SAlexander.Kolbasov@Sun.COM * cross-calls.
214311389SAlexander.Kolbasov@Sun.COM */
214411389SAlexander.Kolbasov@Sun.COM void
kcpc_unprogram(kcpc_ctx_t * ctx,boolean_t cu_interpose)214511389SAlexander.Kolbasov@Sun.COM kcpc_unprogram(kcpc_ctx_t *ctx, boolean_t cu_interpose)
214611389SAlexander.Kolbasov@Sun.COM {
214711389SAlexander.Kolbasov@Sun.COM int error;
214811389SAlexander.Kolbasov@Sun.COM
214911389SAlexander.Kolbasov@Sun.COM ASSERT(IS_HIPIL());
215011389SAlexander.Kolbasov@Sun.COM
215111389SAlexander.Kolbasov@Sun.COM /*
215211389SAlexander.Kolbasov@Sun.COM * CPC context shouldn't be NULL, its CPU field should specify current
215311389SAlexander.Kolbasov@Sun.COM * CPU or be -1 to specify any CPU when the context is bound to a
215411389SAlexander.Kolbasov@Sun.COM * thread, and preemption should be disabled
215511389SAlexander.Kolbasov@Sun.COM */
215611389SAlexander.Kolbasov@Sun.COM ASSERT(ctx != NULL && (ctx->kc_cpuid == CPU->cpu_id ||
215711389SAlexander.Kolbasov@Sun.COM ctx->kc_cpuid == -1) && curthread->t_preempt > 0);
215811389SAlexander.Kolbasov@Sun.COM
215911389SAlexander.Kolbasov@Sun.COM if (ctx == NULL || (ctx->kc_cpuid != CPU->cpu_id &&
216011389SAlexander.Kolbasov@Sun.COM ctx->kc_cpuid != -1) || curthread->t_preempt < 1 ||
216111389SAlexander.Kolbasov@Sun.COM (ctx->kc_flags & KCPC_CTX_INVALID_STOPPED) != 0) {
216211389SAlexander.Kolbasov@Sun.COM return;
216311389SAlexander.Kolbasov@Sun.COM }
216411389SAlexander.Kolbasov@Sun.COM
216511389SAlexander.Kolbasov@Sun.COM /*
216611389SAlexander.Kolbasov@Sun.COM * Specified CPC context to be unprogrammed should be bound to current
216711389SAlexander.Kolbasov@Sun.COM * CPU or thread
216811389SAlexander.Kolbasov@Sun.COM */
216911389SAlexander.Kolbasov@Sun.COM ASSERT(CPU->cpu_cpc_ctx == ctx || curthread->t_cpc_ctx == ctx);
217011389SAlexander.Kolbasov@Sun.COM
217111389SAlexander.Kolbasov@Sun.COM /*
217211389SAlexander.Kolbasov@Sun.COM * Stop counters
217311389SAlexander.Kolbasov@Sun.COM */
217411389SAlexander.Kolbasov@Sun.COM pcbe_ops->pcbe_allstop();
217511389SAlexander.Kolbasov@Sun.COM KCPC_CTX_FLAG_SET(ctx, KCPC_CTX_INVALID_STOPPED);
217611389SAlexander.Kolbasov@Sun.COM
217711389SAlexander.Kolbasov@Sun.COM /*
217811389SAlexander.Kolbasov@Sun.COM * Allow kernel to interpose on counters and program them for its own
217911389SAlexander.Kolbasov@Sun.COM * use to measure hardware capacity and utilization if cu_interpose
218011389SAlexander.Kolbasov@Sun.COM * argument is true
218111389SAlexander.Kolbasov@Sun.COM */
218211389SAlexander.Kolbasov@Sun.COM if (cu_interpose == B_TRUE)
218311389SAlexander.Kolbasov@Sun.COM cu_cpc_program(CPU, &error);
218411389SAlexander.Kolbasov@Sun.COM }
218511389SAlexander.Kolbasov@Sun.COM
218611389SAlexander.Kolbasov@Sun.COM /*
218711389SAlexander.Kolbasov@Sun.COM * Read CPU Performance Counter (CPC) on current CPU and call specified update
218811389SAlexander.Kolbasov@Sun.COM * routine with data for each counter event currently programmed on CPU
218911389SAlexander.Kolbasov@Sun.COM */
219011389SAlexander.Kolbasov@Sun.COM int
kcpc_read(kcpc_update_func_t update_func)219111389SAlexander.Kolbasov@Sun.COM kcpc_read(kcpc_update_func_t update_func)
219211389SAlexander.Kolbasov@Sun.COM {
219311389SAlexander.Kolbasov@Sun.COM kcpc_ctx_t *ctx;
219411389SAlexander.Kolbasov@Sun.COM int i;
219511389SAlexander.Kolbasov@Sun.COM kcpc_request_t *req;
219611389SAlexander.Kolbasov@Sun.COM int retval;
219711389SAlexander.Kolbasov@Sun.COM kcpc_set_t *set;
219811389SAlexander.Kolbasov@Sun.COM
219911389SAlexander.Kolbasov@Sun.COM ASSERT(IS_HIPIL());
220011389SAlexander.Kolbasov@Sun.COM
220111389SAlexander.Kolbasov@Sun.COM /*
220211389SAlexander.Kolbasov@Sun.COM * Can't grab locks or block because may be called inside dispatcher
220311389SAlexander.Kolbasov@Sun.COM */
220411389SAlexander.Kolbasov@Sun.COM kpreempt_disable();
220511389SAlexander.Kolbasov@Sun.COM
220611389SAlexander.Kolbasov@Sun.COM ctx = CPU->cpu_cpc_ctx;
220711389SAlexander.Kolbasov@Sun.COM if (ctx == NULL) {
220811389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
220911389SAlexander.Kolbasov@Sun.COM return (0);
221011389SAlexander.Kolbasov@Sun.COM }
221111389SAlexander.Kolbasov@Sun.COM
221211389SAlexander.Kolbasov@Sun.COM /*
221311389SAlexander.Kolbasov@Sun.COM * Read counter data from current CPU
221411389SAlexander.Kolbasov@Sun.COM */
221511389SAlexander.Kolbasov@Sun.COM pcbe_ops->pcbe_sample(ctx);
221611389SAlexander.Kolbasov@Sun.COM
221711389SAlexander.Kolbasov@Sun.COM set = ctx->kc_set;
221811389SAlexander.Kolbasov@Sun.COM if (set == NULL || set->ks_req == NULL) {
221911389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
222011389SAlexander.Kolbasov@Sun.COM return (0);
222111389SAlexander.Kolbasov@Sun.COM }
222211389SAlexander.Kolbasov@Sun.COM
222311389SAlexander.Kolbasov@Sun.COM /*
222411389SAlexander.Kolbasov@Sun.COM * Call update function with preset pointer and data for each CPC event
222511389SAlexander.Kolbasov@Sun.COM * request currently programmed on current CPU
222611389SAlexander.Kolbasov@Sun.COM */
222711389SAlexander.Kolbasov@Sun.COM req = set->ks_req;
222811389SAlexander.Kolbasov@Sun.COM retval = 0;
222911389SAlexander.Kolbasov@Sun.COM for (i = 0; i < set->ks_nreqs; i++) {
223011389SAlexander.Kolbasov@Sun.COM int ret;
223111389SAlexander.Kolbasov@Sun.COM
223211389SAlexander.Kolbasov@Sun.COM if (req[i].kr_data == NULL)
223311389SAlexander.Kolbasov@Sun.COM break;
223411389SAlexander.Kolbasov@Sun.COM
223511389SAlexander.Kolbasov@Sun.COM ret = update_func(req[i].kr_ptr, *req[i].kr_data);
223611389SAlexander.Kolbasov@Sun.COM if (ret < 0)
223711389SAlexander.Kolbasov@Sun.COM retval = ret;
223811389SAlexander.Kolbasov@Sun.COM }
223911389SAlexander.Kolbasov@Sun.COM
224011389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
224111389SAlexander.Kolbasov@Sun.COM
224211389SAlexander.Kolbasov@Sun.COM return (retval);
224311389SAlexander.Kolbasov@Sun.COM }
224411389SAlexander.Kolbasov@Sun.COM
224511389SAlexander.Kolbasov@Sun.COM /*
224611389SAlexander.Kolbasov@Sun.COM * Initialize list of counter event requests
224711389SAlexander.Kolbasov@Sun.COM */
224811389SAlexander.Kolbasov@Sun.COM kcpc_request_list_t *
kcpc_reqs_init(int nreqs,int kmem_flags)224911389SAlexander.Kolbasov@Sun.COM kcpc_reqs_init(int nreqs, int kmem_flags)
225011389SAlexander.Kolbasov@Sun.COM {
225111389SAlexander.Kolbasov@Sun.COM kcpc_request_list_t *req_list;
225211389SAlexander.Kolbasov@Sun.COM kcpc_request_t *reqs;
225311389SAlexander.Kolbasov@Sun.COM
225411389SAlexander.Kolbasov@Sun.COM if (nreqs < 1)
225511389SAlexander.Kolbasov@Sun.COM return (NULL);
225611389SAlexander.Kolbasov@Sun.COM
225711389SAlexander.Kolbasov@Sun.COM req_list = kmem_zalloc(sizeof (kcpc_request_list_t), kmem_flags);
225811389SAlexander.Kolbasov@Sun.COM if (req_list == NULL)
225911389SAlexander.Kolbasov@Sun.COM return (NULL);
226011389SAlexander.Kolbasov@Sun.COM
226111389SAlexander.Kolbasov@Sun.COM reqs = kmem_zalloc(nreqs * sizeof (kcpc_request_t), kmem_flags);
226211389SAlexander.Kolbasov@Sun.COM if (reqs == NULL) {
226311389SAlexander.Kolbasov@Sun.COM kmem_free(req_list, sizeof (kcpc_request_list_t));
226411389SAlexander.Kolbasov@Sun.COM return (NULL);
226511389SAlexander.Kolbasov@Sun.COM }
226611389SAlexander.Kolbasov@Sun.COM
226711389SAlexander.Kolbasov@Sun.COM req_list->krl_list = reqs;
226811389SAlexander.Kolbasov@Sun.COM req_list->krl_cnt = 0;
226911389SAlexander.Kolbasov@Sun.COM req_list->krl_max = nreqs;
227011389SAlexander.Kolbasov@Sun.COM return (req_list);
227111389SAlexander.Kolbasov@Sun.COM }
227211389SAlexander.Kolbasov@Sun.COM
227311389SAlexander.Kolbasov@Sun.COM
227411389SAlexander.Kolbasov@Sun.COM /*
227511389SAlexander.Kolbasov@Sun.COM * Add counter event request to given list of counter event requests
227611389SAlexander.Kolbasov@Sun.COM */
227711389SAlexander.Kolbasov@Sun.COM int
kcpc_reqs_add(kcpc_request_list_t * req_list,char * event,uint64_t preset,uint_t flags,uint_t nattrs,kcpc_attr_t * attr,void * ptr,int kmem_flags)227811389SAlexander.Kolbasov@Sun.COM kcpc_reqs_add(kcpc_request_list_t *req_list, char *event, uint64_t preset,
227911389SAlexander.Kolbasov@Sun.COM uint_t flags, uint_t nattrs, kcpc_attr_t *attr, void *ptr, int kmem_flags)
228011389SAlexander.Kolbasov@Sun.COM {
228111389SAlexander.Kolbasov@Sun.COM kcpc_request_t *req;
228211389SAlexander.Kolbasov@Sun.COM
228311389SAlexander.Kolbasov@Sun.COM if (req_list == NULL || req_list->krl_list == NULL)
228411389SAlexander.Kolbasov@Sun.COM return (-1);
228511389SAlexander.Kolbasov@Sun.COM
2286*13070SEthindra.Ramamurthy@Sun.COM ASSERT(req_list->krl_max != 0);
2287*13070SEthindra.Ramamurthy@Sun.COM
228811389SAlexander.Kolbasov@Sun.COM /*
228911389SAlexander.Kolbasov@Sun.COM * Allocate more space (if needed)
229011389SAlexander.Kolbasov@Sun.COM */
229111389SAlexander.Kolbasov@Sun.COM if (req_list->krl_cnt > req_list->krl_max) {
229211389SAlexander.Kolbasov@Sun.COM kcpc_request_t *new;
229311389SAlexander.Kolbasov@Sun.COM kcpc_request_t *old;
229411389SAlexander.Kolbasov@Sun.COM
229511389SAlexander.Kolbasov@Sun.COM old = req_list->krl_list;
229611389SAlexander.Kolbasov@Sun.COM new = kmem_zalloc((req_list->krl_max +
229711389SAlexander.Kolbasov@Sun.COM cpc_ncounters) * sizeof (kcpc_request_t), kmem_flags);
229811389SAlexander.Kolbasov@Sun.COM if (new == NULL)
229911389SAlexander.Kolbasov@Sun.COM return (-2);
230011389SAlexander.Kolbasov@Sun.COM
230111389SAlexander.Kolbasov@Sun.COM req_list->krl_list = new;
230211389SAlexander.Kolbasov@Sun.COM bcopy(old, req_list->krl_list,
230311389SAlexander.Kolbasov@Sun.COM req_list->krl_cnt * sizeof (kcpc_request_t));
230411389SAlexander.Kolbasov@Sun.COM kmem_free(old, req_list->krl_max * sizeof (kcpc_request_t));
230511389SAlexander.Kolbasov@Sun.COM req_list->krl_cnt = 0;
230611389SAlexander.Kolbasov@Sun.COM req_list->krl_max += cpc_ncounters;
230711389SAlexander.Kolbasov@Sun.COM }
230811389SAlexander.Kolbasov@Sun.COM
230911389SAlexander.Kolbasov@Sun.COM /*
231011389SAlexander.Kolbasov@Sun.COM * Fill in request as much as possible now, but some fields will need
231111389SAlexander.Kolbasov@Sun.COM * to be set when request is assigned to a set.
231211389SAlexander.Kolbasov@Sun.COM */
231311389SAlexander.Kolbasov@Sun.COM req = &req_list->krl_list[req_list->krl_cnt];
231411389SAlexander.Kolbasov@Sun.COM req->kr_config = NULL;
231511389SAlexander.Kolbasov@Sun.COM req->kr_picnum = -1; /* have CPC pick this */
231611389SAlexander.Kolbasov@Sun.COM req->kr_index = -1; /* set when assigning request to set */
231711389SAlexander.Kolbasov@Sun.COM req->kr_data = NULL; /* set when configuring request */
231811389SAlexander.Kolbasov@Sun.COM (void) strcpy(req->kr_event, event);
231911389SAlexander.Kolbasov@Sun.COM req->kr_preset = preset;
232011389SAlexander.Kolbasov@Sun.COM req->kr_flags = flags;
232111389SAlexander.Kolbasov@Sun.COM req->kr_nattrs = nattrs;
232211389SAlexander.Kolbasov@Sun.COM req->kr_attr = attr;
232311389SAlexander.Kolbasov@Sun.COM /*
232411389SAlexander.Kolbasov@Sun.COM * Keep pointer given by caller to give to update function when this
232511389SAlexander.Kolbasov@Sun.COM * counter event is sampled/read
232611389SAlexander.Kolbasov@Sun.COM */
232711389SAlexander.Kolbasov@Sun.COM req->kr_ptr = ptr;
232811389SAlexander.Kolbasov@Sun.COM
232911389SAlexander.Kolbasov@Sun.COM req_list->krl_cnt++;
233011389SAlexander.Kolbasov@Sun.COM
233111389SAlexander.Kolbasov@Sun.COM return (0);
233211389SAlexander.Kolbasov@Sun.COM }
233311389SAlexander.Kolbasov@Sun.COM
233411389SAlexander.Kolbasov@Sun.COM /*
233511389SAlexander.Kolbasov@Sun.COM * Reset list of CPC event requests so its space can be used for another set
233611389SAlexander.Kolbasov@Sun.COM * of requests
233711389SAlexander.Kolbasov@Sun.COM */
233811389SAlexander.Kolbasov@Sun.COM int
kcpc_reqs_reset(kcpc_request_list_t * req_list)233911389SAlexander.Kolbasov@Sun.COM kcpc_reqs_reset(kcpc_request_list_t *req_list)
234011389SAlexander.Kolbasov@Sun.COM {
234111389SAlexander.Kolbasov@Sun.COM /*
234211389SAlexander.Kolbasov@Sun.COM * Return when pointer to request list structure or request is NULL or
234311389SAlexander.Kolbasov@Sun.COM * when max requests is less than or equal to 0
234411389SAlexander.Kolbasov@Sun.COM */
234511389SAlexander.Kolbasov@Sun.COM if (req_list == NULL || req_list->krl_list == NULL ||
234611389SAlexander.Kolbasov@Sun.COM req_list->krl_max <= 0)
234711389SAlexander.Kolbasov@Sun.COM return (-1);
234811389SAlexander.Kolbasov@Sun.COM
234911389SAlexander.Kolbasov@Sun.COM /*
235011389SAlexander.Kolbasov@Sun.COM * Zero out requests and number of requests used
235111389SAlexander.Kolbasov@Sun.COM */
235211389SAlexander.Kolbasov@Sun.COM bzero(req_list->krl_list, req_list->krl_max * sizeof (kcpc_request_t));
235311389SAlexander.Kolbasov@Sun.COM req_list->krl_cnt = 0;
235411389SAlexander.Kolbasov@Sun.COM return (0);
235511389SAlexander.Kolbasov@Sun.COM }
235611389SAlexander.Kolbasov@Sun.COM
235711389SAlexander.Kolbasov@Sun.COM /*
235811389SAlexander.Kolbasov@Sun.COM * Free given list of counter event requests
235911389SAlexander.Kolbasov@Sun.COM */
236011389SAlexander.Kolbasov@Sun.COM int
kcpc_reqs_fini(kcpc_request_list_t * req_list)236111389SAlexander.Kolbasov@Sun.COM kcpc_reqs_fini(kcpc_request_list_t *req_list)
236211389SAlexander.Kolbasov@Sun.COM {
236311389SAlexander.Kolbasov@Sun.COM kmem_free(req_list->krl_list,
236411389SAlexander.Kolbasov@Sun.COM req_list->krl_max * sizeof (kcpc_request_t));
236511389SAlexander.Kolbasov@Sun.COM kmem_free(req_list, sizeof (kcpc_request_list_t));
236611389SAlexander.Kolbasov@Sun.COM return (0);
236711389SAlexander.Kolbasov@Sun.COM }
236811389SAlexander.Kolbasov@Sun.COM
236911389SAlexander.Kolbasov@Sun.COM /*
237011389SAlexander.Kolbasov@Sun.COM * Create set of given counter event requests
237111389SAlexander.Kolbasov@Sun.COM */
237211389SAlexander.Kolbasov@Sun.COM static kcpc_set_t *
kcpc_set_create(kcpc_request_t * reqs,int nreqs,int set_flags,int kmem_flags)237311389SAlexander.Kolbasov@Sun.COM kcpc_set_create(kcpc_request_t *reqs, int nreqs, int set_flags, int kmem_flags)
237411389SAlexander.Kolbasov@Sun.COM {
237511389SAlexander.Kolbasov@Sun.COM int i;
237611389SAlexander.Kolbasov@Sun.COM kcpc_set_t *set;
237711389SAlexander.Kolbasov@Sun.COM
237811389SAlexander.Kolbasov@Sun.COM /*
237911389SAlexander.Kolbasov@Sun.COM * Allocate set and assign number of requests in set and flags
238011389SAlexander.Kolbasov@Sun.COM */
238111389SAlexander.Kolbasov@Sun.COM set = kmem_zalloc(sizeof (kcpc_set_t), kmem_flags);
238211389SAlexander.Kolbasov@Sun.COM if (set == NULL)
238311389SAlexander.Kolbasov@Sun.COM return (NULL);
238411389SAlexander.Kolbasov@Sun.COM
238511389SAlexander.Kolbasov@Sun.COM if (nreqs < cpc_ncounters)
238611389SAlexander.Kolbasov@Sun.COM set->ks_nreqs = nreqs;
238711389SAlexander.Kolbasov@Sun.COM else
238811389SAlexander.Kolbasov@Sun.COM set->ks_nreqs = cpc_ncounters;
238911389SAlexander.Kolbasov@Sun.COM
239011389SAlexander.Kolbasov@Sun.COM set->ks_flags = set_flags;
239111389SAlexander.Kolbasov@Sun.COM
239211389SAlexander.Kolbasov@Sun.COM /*
239311389SAlexander.Kolbasov@Sun.COM * Allocate requests needed, copy requests into set, and set index into
239411389SAlexander.Kolbasov@Sun.COM * data for each request (which may change when we assign requested
239511389SAlexander.Kolbasov@Sun.COM * counter events to counters)
239611389SAlexander.Kolbasov@Sun.COM */
239711389SAlexander.Kolbasov@Sun.COM set->ks_req = (kcpc_request_t *)kmem_zalloc(sizeof (kcpc_request_t) *
239811389SAlexander.Kolbasov@Sun.COM set->ks_nreqs, kmem_flags);
239911389SAlexander.Kolbasov@Sun.COM if (set->ks_req == NULL) {
240011389SAlexander.Kolbasov@Sun.COM kmem_free(set, sizeof (kcpc_set_t));
240111389SAlexander.Kolbasov@Sun.COM return (NULL);
240211389SAlexander.Kolbasov@Sun.COM }
240311389SAlexander.Kolbasov@Sun.COM
240411389SAlexander.Kolbasov@Sun.COM bcopy(reqs, set->ks_req, sizeof (kcpc_request_t) * set->ks_nreqs);
240511389SAlexander.Kolbasov@Sun.COM
240611389SAlexander.Kolbasov@Sun.COM for (i = 0; i < set->ks_nreqs; i++)
240711389SAlexander.Kolbasov@Sun.COM set->ks_req[i].kr_index = i;
240811389SAlexander.Kolbasov@Sun.COM
240911389SAlexander.Kolbasov@Sun.COM return (set);
241011389SAlexander.Kolbasov@Sun.COM }
241111389SAlexander.Kolbasov@Sun.COM
241211389SAlexander.Kolbasov@Sun.COM
241311389SAlexander.Kolbasov@Sun.COM /*
241411389SAlexander.Kolbasov@Sun.COM * Stop counters on current CPU.
241511389SAlexander.Kolbasov@Sun.COM *
241611389SAlexander.Kolbasov@Sun.COM * If preserve_context is true, the caller is interested in the CPU's CPC
241711389SAlexander.Kolbasov@Sun.COM * context and wants it to be preserved.
241811389SAlexander.Kolbasov@Sun.COM *
241911389SAlexander.Kolbasov@Sun.COM * If preserve_context is false, the caller does not need the CPU's CPC context
242011389SAlexander.Kolbasov@Sun.COM * to be preserved, so it is set to NULL.
242111389SAlexander.Kolbasov@Sun.COM */
242211389SAlexander.Kolbasov@Sun.COM static void
kcpc_cpustop_func(boolean_t preserve_context)242311389SAlexander.Kolbasov@Sun.COM kcpc_cpustop_func(boolean_t preserve_context)
242411389SAlexander.Kolbasov@Sun.COM {
242511389SAlexander.Kolbasov@Sun.COM kpreempt_disable();
242611389SAlexander.Kolbasov@Sun.COM
242711389SAlexander.Kolbasov@Sun.COM /*
242811389SAlexander.Kolbasov@Sun.COM * Someone already stopped this context before us, so there is nothing
242911389SAlexander.Kolbasov@Sun.COM * to do.
243011389SAlexander.Kolbasov@Sun.COM */
243111389SAlexander.Kolbasov@Sun.COM if (CPU->cpu_cpc_ctx == NULL) {
243211389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
243311389SAlexander.Kolbasov@Sun.COM return;
243411389SAlexander.Kolbasov@Sun.COM }
243511389SAlexander.Kolbasov@Sun.COM
243611389SAlexander.Kolbasov@Sun.COM kcpc_unprogram(CPU->cpu_cpc_ctx, B_TRUE);
243711389SAlexander.Kolbasov@Sun.COM /*
243811389SAlexander.Kolbasov@Sun.COM * If CU does not use counters, then clear the CPU's CPC context
243911389SAlexander.Kolbasov@Sun.COM * If the caller requested to preserve context it should disable CU
244011389SAlexander.Kolbasov@Sun.COM * first, so there should be no CU context now.
244111389SAlexander.Kolbasov@Sun.COM */
244211389SAlexander.Kolbasov@Sun.COM ASSERT(!preserve_context || !CU_CPC_ON(CPU));
244311389SAlexander.Kolbasov@Sun.COM if (!preserve_context && CPU->cpu_cpc_ctx != NULL && !CU_CPC_ON(CPU))
244411389SAlexander.Kolbasov@Sun.COM CPU->cpu_cpc_ctx = NULL;
244511389SAlexander.Kolbasov@Sun.COM
244611389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
244711389SAlexander.Kolbasov@Sun.COM }
244811389SAlexander.Kolbasov@Sun.COM
244911389SAlexander.Kolbasov@Sun.COM /*
245011389SAlexander.Kolbasov@Sun.COM * Stop counters on given CPU and set its CPC context to NULL unless
245111389SAlexander.Kolbasov@Sun.COM * preserve_context is true.
245211389SAlexander.Kolbasov@Sun.COM */
245311389SAlexander.Kolbasov@Sun.COM void
kcpc_cpu_stop(cpu_t * cp,boolean_t preserve_context)245411389SAlexander.Kolbasov@Sun.COM kcpc_cpu_stop(cpu_t *cp, boolean_t preserve_context)
245511389SAlexander.Kolbasov@Sun.COM {
245611389SAlexander.Kolbasov@Sun.COM cpu_call(cp, (cpu_call_func_t)kcpc_cpustop_func,
245711389SAlexander.Kolbasov@Sun.COM preserve_context, 0);
245811389SAlexander.Kolbasov@Sun.COM }
245911389SAlexander.Kolbasov@Sun.COM
246011389SAlexander.Kolbasov@Sun.COM /*
246111389SAlexander.Kolbasov@Sun.COM * Program the context on the current CPU
246211389SAlexander.Kolbasov@Sun.COM */
246311389SAlexander.Kolbasov@Sun.COM static void
kcpc_remoteprogram_func(kcpc_ctx_t * ctx,uintptr_t arg)246411389SAlexander.Kolbasov@Sun.COM kcpc_remoteprogram_func(kcpc_ctx_t *ctx, uintptr_t arg)
246511389SAlexander.Kolbasov@Sun.COM {
246611389SAlexander.Kolbasov@Sun.COM boolean_t for_thread = (boolean_t)arg;
246711389SAlexander.Kolbasov@Sun.COM
246811389SAlexander.Kolbasov@Sun.COM ASSERT(ctx != NULL);
246911389SAlexander.Kolbasov@Sun.COM
247011389SAlexander.Kolbasov@Sun.COM kpreempt_disable();
247111389SAlexander.Kolbasov@Sun.COM kcpc_program(ctx, for_thread, B_TRUE);
247211389SAlexander.Kolbasov@Sun.COM kpreempt_enable();
247311389SAlexander.Kolbasov@Sun.COM }
247411389SAlexander.Kolbasov@Sun.COM
247511389SAlexander.Kolbasov@Sun.COM /*
247611389SAlexander.Kolbasov@Sun.COM * Program counters on given CPU
247711389SAlexander.Kolbasov@Sun.COM */
247811389SAlexander.Kolbasov@Sun.COM void
kcpc_cpu_program(cpu_t * cp,kcpc_ctx_t * ctx)247911389SAlexander.Kolbasov@Sun.COM kcpc_cpu_program(cpu_t *cp, kcpc_ctx_t *ctx)
248011389SAlexander.Kolbasov@Sun.COM {
248111389SAlexander.Kolbasov@Sun.COM cpu_call(cp, (cpu_call_func_t)kcpc_remoteprogram_func, (uintptr_t)ctx,
248211389SAlexander.Kolbasov@Sun.COM (uintptr_t)B_FALSE);
248311389SAlexander.Kolbasov@Sun.COM }
248411389SAlexander.Kolbasov@Sun.COM
24858803SJonathan.Haslam@Sun.COM char *
kcpc_list_attrs(void)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 *
kcpc_list_events(uint_t pic)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
kcpc_pcbe_capabilities(void)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
kcpc_pcbe_loaded(void)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