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