xref: /titanic_44/usr/src/uts/common/dtrace/dcpc.c (revision 8cb74972a66bde0af7b1a957d01e0095b82a8b91)
1b9e93c10SJonathan Haslam /*
2b9e93c10SJonathan Haslam  * CDDL HEADER START
3b9e93c10SJonathan Haslam  *
4b9e93c10SJonathan Haslam  * The contents of this file are subject to the terms of the
5b9e93c10SJonathan Haslam  * Common Development and Distribution License (the "License").
6b9e93c10SJonathan Haslam  * You may not use this file except in compliance with the License.
7b9e93c10SJonathan Haslam  *
8b9e93c10SJonathan Haslam  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9b9e93c10SJonathan Haslam  * or http://www.opensolaris.org/os/licensing.
10b9e93c10SJonathan Haslam  * See the License for the specific language governing permissions
11b9e93c10SJonathan Haslam  * and limitations under the License.
12b9e93c10SJonathan Haslam  *
13b9e93c10SJonathan Haslam  * When distributing Covered Code, include this CDDL HEADER in each
14b9e93c10SJonathan Haslam  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15b9e93c10SJonathan Haslam  * If applicable, add the following below this CDDL HEADER, with the
16b9e93c10SJonathan Haslam  * fields enclosed by brackets "[]" replaced with your own identifying
17b9e93c10SJonathan Haslam  * information: Portions Copyright [yyyy] [name of copyright owner]
18b9e93c10SJonathan Haslam  *
19b9e93c10SJonathan Haslam  * CDDL HEADER END
20b9e93c10SJonathan Haslam  */
21b9e93c10SJonathan Haslam 
22b9e93c10SJonathan Haslam /*
23b9e93c10SJonathan Haslam  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24b9e93c10SJonathan Haslam  * Use is subject to license terms.
25b9e93c10SJonathan Haslam  */
26b9e93c10SJonathan Haslam 
27b9e93c10SJonathan Haslam #include <sys/errno.h>
28b9e93c10SJonathan Haslam #include <sys/cpuvar.h>
29b9e93c10SJonathan Haslam #include <sys/stat.h>
30b9e93c10SJonathan Haslam #include <sys/modctl.h>
31b9e93c10SJonathan Haslam #include <sys/cmn_err.h>
32b9e93c10SJonathan Haslam #include <sys/ddi.h>
33b9e93c10SJonathan Haslam #include <sys/sunddi.h>
34b9e93c10SJonathan Haslam #include <sys/ksynch.h>
35b9e93c10SJonathan Haslam #include <sys/conf.h>
36b9e93c10SJonathan Haslam #include <sys/kmem.h>
37b9e93c10SJonathan Haslam #include <sys/kcpc.h>
38b9e93c10SJonathan Haslam #include <sys/cpc_pcbe.h>
39b9e93c10SJonathan Haslam #include <sys/cpc_impl.h>
40b9e93c10SJonathan Haslam #include <sys/dtrace_impl.h>
41b9e93c10SJonathan Haslam 
42b9e93c10SJonathan Haslam /*
43b9e93c10SJonathan Haslam  * DTrace CPU Performance Counter Provider
44b9e93c10SJonathan Haslam  * ---------------------------------------
45b9e93c10SJonathan Haslam  *
46b9e93c10SJonathan Haslam  * The DTrace cpc provider allows DTrace consumers to access the CPU
47b9e93c10SJonathan Haslam  * performance counter overflow mechanism of a CPU. The configuration
48b9e93c10SJonathan Haslam  * presented in a probe specification is programmed into the performance
49b9e93c10SJonathan Haslam  * counter hardware of all available CPUs on a system. Programming the
50b9e93c10SJonathan Haslam  * hardware causes a counter on each CPU to begin counting events of the
51b9e93c10SJonathan Haslam  * given type. When the specified number of events have occurred, an overflow
52b9e93c10SJonathan Haslam  * interrupt will be generated and the probe is fired.
53b9e93c10SJonathan Haslam  *
54b9e93c10SJonathan Haslam  * The required configuration for the performance counter is encoded into
55b9e93c10SJonathan Haslam  * the probe specification and this includes the performance counter event
56b9e93c10SJonathan Haslam  * name, processor mode, overflow rate and an optional unit mask.
57b9e93c10SJonathan Haslam  *
58b9e93c10SJonathan Haslam  * Most processors provide several counters (PICs) which can count all or a
59b9e93c10SJonathan Haslam  * subset of the events available for a given CPU. However, when overflow
60b9e93c10SJonathan Haslam  * profiling is being used, not all CPUs can detect which counter generated the
61b9e93c10SJonathan Haslam  * overflow interrupt. In this case we cannot reliably determine which counter
62b9e93c10SJonathan Haslam  * overflowed and we therefore only allow such CPUs to configure one event at
63b9e93c10SJonathan Haslam  * a time. Processors that can determine the counter which overflowed are
64b9e93c10SJonathan Haslam  * allowed to program as many events at one time as possible (in theory up to
65b9e93c10SJonathan Haslam  * the number of instrumentation counters supported by that platform).
66b9e93c10SJonathan Haslam  * Therefore, multiple consumers can enable multiple probes at the same time
67b9e93c10SJonathan Haslam  * on such platforms. Platforms which cannot determine the source of an
68b9e93c10SJonathan Haslam  * overflow interrupt are only allowed to program a single event at one time.
69b9e93c10SJonathan Haslam  *
70b9e93c10SJonathan Haslam  * The performance counter hardware is made available to consumers on a
71b9e93c10SJonathan Haslam  * first-come, first-served basis. Only a finite amount of hardware resource
72b9e93c10SJonathan Haslam  * is available and, while we make every attempt to accomodate requests from
73b9e93c10SJonathan Haslam  * consumers, we must deny requests when hardware resources have been exhausted.
74b9e93c10SJonathan Haslam  * A consumer will fail to enable probes when resources are currently in use.
75b9e93c10SJonathan Haslam  *
76b9e93c10SJonathan Haslam  * The cpc provider contends for shared hardware resources along with other
77b9e93c10SJonathan Haslam  * consumers of the kernel CPU performance counter subsystem (e.g. cpustat(1M)).
78b9e93c10SJonathan Haslam  * Only one such consumer can use the performance counters at any one time and
79b9e93c10SJonathan Haslam  * counters are made available on a first-come, first-served basis. As with
80b9e93c10SJonathan Haslam  * cpustat, the cpc provider has priority over per-LWP libcpc usage (e.g.
81b9e93c10SJonathan Haslam  * cputrack(1)). Invoking the cpc provider will cause all existing per-LWP
82b9e93c10SJonathan Haslam  * counter contexts to be invalidated.
83b9e93c10SJonathan Haslam  */
84b9e93c10SJonathan Haslam 
85b9e93c10SJonathan Haslam typedef struct dcpc_probe {
86b9e93c10SJonathan Haslam 	char		dcpc_event_name[CPC_MAX_EVENT_LEN];
87b9e93c10SJonathan Haslam 	int		dcpc_flag;	/* flags (USER/SYS) */
88b9e93c10SJonathan Haslam 	uint32_t	dcpc_ovfval;	/* overflow value */
89b9e93c10SJonathan Haslam 	int64_t		dcpc_umask;	/* umask/emask for this event */
90b9e93c10SJonathan Haslam 	int		dcpc_picno;	/* pic this event is programmed in */
91b9e93c10SJonathan Haslam 	int		dcpc_enabled;	/* probe is actually enabled? */
92b9e93c10SJonathan Haslam 	int		dcpc_disabling;	/* probe is currently being disabled */
93b9e93c10SJonathan Haslam 	dtrace_id_t	dcpc_id;	/* probeid this request is enabling */
94b9e93c10SJonathan Haslam 	int		dcpc_actv_req_idx;	/* idx into dcpc_actv_reqs[] */
95b9e93c10SJonathan Haslam } dcpc_probe_t;
96b9e93c10SJonathan Haslam 
97b9e93c10SJonathan Haslam static dev_info_t			*dcpc_devi;
98b9e93c10SJonathan Haslam static dtrace_provider_id_t		dcpc_pid;
99b9e93c10SJonathan Haslam static dcpc_probe_t			**dcpc_actv_reqs;
100b9e93c10SJonathan Haslam static uint32_t				dcpc_enablings = 0;
101b9e93c10SJonathan Haslam static int				dcpc_ovf_mask = 0;
102b9e93c10SJonathan Haslam static int				dcpc_mult_ovf_cap = 0;
103b9e93c10SJonathan Haslam static int				dcpc_mask_type = 0;
104b9e93c10SJonathan Haslam 
105b9e93c10SJonathan Haslam /*
106b9e93c10SJonathan Haslam  * When the dcpc provider is loaded, dcpc_min_overflow is set to either
107b9e93c10SJonathan Haslam  * DCPC_MIN_OVF_DEFAULT or the value that dcpc-min-overflow is set to in
108b9e93c10SJonathan Haslam  * the dcpc.conf file. Decrease this value to set probes with smaller
109b9e93c10SJonathan Haslam  * overflow values. Remember that very small values could render a system
110b9e93c10SJonathan Haslam  * unusable with frequently occurring events.
111b9e93c10SJonathan Haslam  */
112b9e93c10SJonathan Haslam #define	DCPC_MIN_OVF_DEFAULT		5000
113b9e93c10SJonathan Haslam static uint32_t				dcpc_min_overflow;
114b9e93c10SJonathan Haslam 
115b9e93c10SJonathan Haslam static int dcpc_aframes = 0;	/* override for artificial frame setting */
116b9e93c10SJonathan Haslam #if defined(__x86)
117b9e93c10SJonathan Haslam #define	DCPC_ARTIFICIAL_FRAMES	8
118b9e93c10SJonathan Haslam #elif defined(__sparc)
119b9e93c10SJonathan Haslam #define	DCPC_ARTIFICIAL_FRAMES	2
120b9e93c10SJonathan Haslam #endif
121b9e93c10SJonathan Haslam 
122b9e93c10SJonathan Haslam /*
123b9e93c10SJonathan Haslam  * Called from the platform overflow interrupt handler. 'bitmap' is a mask
124b9e93c10SJonathan Haslam  * which contains the pic(s) that have overflowed.
125b9e93c10SJonathan Haslam  */
126b9e93c10SJonathan Haslam static void
127b9e93c10SJonathan Haslam dcpc_fire(uint64_t bitmap)
128b9e93c10SJonathan Haslam {
129b9e93c10SJonathan Haslam 	int i;
130b9e93c10SJonathan Haslam 
131b9e93c10SJonathan Haslam 	/*
132b9e93c10SJonathan Haslam 	 * No counter was marked as overflowing. Shout about it and get out.
133b9e93c10SJonathan Haslam 	 */
134b9e93c10SJonathan Haslam 	if ((bitmap & dcpc_ovf_mask) == 0) {
135b9e93c10SJonathan Haslam 		cmn_err(CE_NOTE, "dcpc_fire: no counter overflow found\n");
136b9e93c10SJonathan Haslam 		return;
137b9e93c10SJonathan Haslam 	}
138b9e93c10SJonathan Haslam 
139b9e93c10SJonathan Haslam 	/*
140b9e93c10SJonathan Haslam 	 * This is the common case of a processor that doesn't support
141b9e93c10SJonathan Haslam 	 * multiple overflow events. Such systems are only allowed a single
142b9e93c10SJonathan Haslam 	 * enabling and therefore we just look for the first entry in
143b9e93c10SJonathan Haslam 	 * the active request array.
144b9e93c10SJonathan Haslam 	 */
145b9e93c10SJonathan Haslam 	if (!dcpc_mult_ovf_cap) {
146b9e93c10SJonathan Haslam 		for (i = 0; i < cpc_ncounters; i++) {
147b9e93c10SJonathan Haslam 			if (dcpc_actv_reqs[i] != NULL) {
148b9e93c10SJonathan Haslam 				dtrace_probe(dcpc_actv_reqs[i]->dcpc_id,
149b9e93c10SJonathan Haslam 				    CPU->cpu_cpcprofile_pc,
150b9e93c10SJonathan Haslam 				    CPU->cpu_cpcprofile_upc, 0, 0, 0);
151b9e93c10SJonathan Haslam 				return;
152b9e93c10SJonathan Haslam 			}
153b9e93c10SJonathan Haslam 		}
154b9e93c10SJonathan Haslam 		return;
155b9e93c10SJonathan Haslam 	}
156b9e93c10SJonathan Haslam 
157b9e93c10SJonathan Haslam 	/*
158b9e93c10SJonathan Haslam 	 * This is a processor capable of handling multiple overflow events.
159b9e93c10SJonathan Haslam 	 * Iterate over the array of active requests and locate the counters
160b9e93c10SJonathan Haslam 	 * that overflowed (note: it is possible for more than one counter to
161b9e93c10SJonathan Haslam 	 * have overflowed at the same time).
162b9e93c10SJonathan Haslam 	 */
163b9e93c10SJonathan Haslam 	for (i = 0; i < cpc_ncounters; i++) {
164b9e93c10SJonathan Haslam 		if (dcpc_actv_reqs[i] != NULL &&
165b9e93c10SJonathan Haslam 		    (bitmap & (1ULL << dcpc_actv_reqs[i]->dcpc_picno))) {
166b9e93c10SJonathan Haslam 			dtrace_probe(dcpc_actv_reqs[i]->dcpc_id,
167b9e93c10SJonathan Haslam 			    CPU->cpu_cpcprofile_pc,
168b9e93c10SJonathan Haslam 			    CPU->cpu_cpcprofile_upc, 0, 0, 0);
169b9e93c10SJonathan Haslam 		}
170b9e93c10SJonathan Haslam 	}
171b9e93c10SJonathan Haslam }
172b9e93c10SJonathan Haslam 
173b9e93c10SJonathan Haslam static void
174b9e93c10SJonathan Haslam dcpc_create_probe(dtrace_provider_id_t id, const char *probename,
175b9e93c10SJonathan Haslam     char *eventname, int64_t umask, uint32_t ovfval, char flag)
176b9e93c10SJonathan Haslam {
177b9e93c10SJonathan Haslam 	dcpc_probe_t *pp;
178b9e93c10SJonathan Haslam 	int nr_frames = DCPC_ARTIFICIAL_FRAMES + dtrace_mach_aframes();
179b9e93c10SJonathan Haslam 
180b9e93c10SJonathan Haslam 	if (dcpc_aframes)
181b9e93c10SJonathan Haslam 		nr_frames = dcpc_aframes;
182b9e93c10SJonathan Haslam 
183b9e93c10SJonathan Haslam 	if (dtrace_probe_lookup(id, NULL, NULL, probename) != 0)
184b9e93c10SJonathan Haslam 		return;
185b9e93c10SJonathan Haslam 
186b9e93c10SJonathan Haslam 	pp = kmem_zalloc(sizeof (dcpc_probe_t), KM_SLEEP);
187b9e93c10SJonathan Haslam 	(void) strncpy(pp->dcpc_event_name, eventname,
188b9e93c10SJonathan Haslam 	    sizeof (pp->dcpc_event_name) - 1);
189b9e93c10SJonathan Haslam 	pp->dcpc_event_name[sizeof (pp->dcpc_event_name) - 1] = '\0';
190b9e93c10SJonathan Haslam 	pp->dcpc_flag = flag | CPC_OVF_NOTIFY_EMT;
191b9e93c10SJonathan Haslam 	pp->dcpc_ovfval = ovfval;
192b9e93c10SJonathan Haslam 	pp->dcpc_umask = umask;
193b9e93c10SJonathan Haslam 	pp->dcpc_actv_req_idx = pp->dcpc_picno = pp->dcpc_disabling = -1;
194b9e93c10SJonathan Haslam 
195b9e93c10SJonathan Haslam 	pp->dcpc_id = dtrace_probe_create(id, NULL, NULL, probename,
196b9e93c10SJonathan Haslam 	    nr_frames, pp);
197b9e93c10SJonathan Haslam }
198b9e93c10SJonathan Haslam 
199b9e93c10SJonathan Haslam /*ARGSUSED*/
200b9e93c10SJonathan Haslam static void
201b9e93c10SJonathan Haslam dcpc_provide(void *arg, const dtrace_probedesc_t *desc)
202b9e93c10SJonathan Haslam {
203b9e93c10SJonathan Haslam 	/*
204b9e93c10SJonathan Haslam 	 * The format of a probe is:
205b9e93c10SJonathan Haslam 	 *
206b9e93c10SJonathan Haslam 	 *	event_name-mode-{optional_umask}-overflow_rate
207b9e93c10SJonathan Haslam 	 * e.g.
208b9e93c10SJonathan Haslam 	 *	DC_refill_from_system-user-0x1e-50000, or,
209b9e93c10SJonathan Haslam 	 *	DC_refill_from_system-all-10000
210b9e93c10SJonathan Haslam 	 *
211b9e93c10SJonathan Haslam 	 */
212b9e93c10SJonathan Haslam 	char *str, *end, *p;
213b9e93c10SJonathan Haslam 	int i, flag = 0;
214b9e93c10SJonathan Haslam 	char event[CPC_MAX_EVENT_LEN];
215b9e93c10SJonathan Haslam 	long umask = -1, val = 0;
216b9e93c10SJonathan Haslam 	size_t evlen, len;
217b9e93c10SJonathan Haslam 
218b9e93c10SJonathan Haslam 	/*
219b9e93c10SJonathan Haslam 	 * The 'cpc' provider offers no probes by default.
220b9e93c10SJonathan Haslam 	 */
221b9e93c10SJonathan Haslam 	if (desc == NULL)
222b9e93c10SJonathan Haslam 		return;
223b9e93c10SJonathan Haslam 
224b9e93c10SJonathan Haslam 	len = strlen(desc->dtpd_name);
225b9e93c10SJonathan Haslam 	p = str = kmem_alloc(len + 1, KM_SLEEP);
226b9e93c10SJonathan Haslam 	(void) strcpy(str, desc->dtpd_name);
227b9e93c10SJonathan Haslam 
228b9e93c10SJonathan Haslam 	/*
229b9e93c10SJonathan Haslam 	 * We have a poor man's strtok() going on here. Replace any hyphens
230b9e93c10SJonathan Haslam 	 * in the the probe name with NULL characters in order to make it
231b9e93c10SJonathan Haslam 	 * easy to parse the string with regular string functions.
232b9e93c10SJonathan Haslam 	 */
233b9e93c10SJonathan Haslam 	for (i = 0; i < len; i++) {
234b9e93c10SJonathan Haslam 		if (str[i] == '-')
235b9e93c10SJonathan Haslam 			str[i] = '\0';
236b9e93c10SJonathan Haslam 	}
237b9e93c10SJonathan Haslam 
238b9e93c10SJonathan Haslam 	/*
239b9e93c10SJonathan Haslam 	 * The first part of the string must be either a platform event
240b9e93c10SJonathan Haslam 	 * name or a generic event name.
241b9e93c10SJonathan Haslam 	 */
242b9e93c10SJonathan Haslam 	evlen = strlen(p);
243b9e93c10SJonathan Haslam 	(void) strncpy(event, p, CPC_MAX_EVENT_LEN - 1);
244b9e93c10SJonathan Haslam 	event[CPC_MAX_EVENT_LEN - 1] = '\0';
245b9e93c10SJonathan Haslam 
246b9e93c10SJonathan Haslam 	/*
247b9e93c10SJonathan Haslam 	 * The next part of the name is the mode specification. Valid
248b9e93c10SJonathan Haslam 	 * settings are "user", "kernel" or "all".
249b9e93c10SJonathan Haslam 	 */
250b9e93c10SJonathan Haslam 	p += evlen + 1;
251b9e93c10SJonathan Haslam 
252b9e93c10SJonathan Haslam 	if (strcmp(p, "user") == 0)
253b9e93c10SJonathan Haslam 		flag |= CPC_COUNT_USER;
254b9e93c10SJonathan Haslam 	else if (strcmp(p, "kernel") == 0)
255b9e93c10SJonathan Haslam 		flag |= CPC_COUNT_SYSTEM;
256b9e93c10SJonathan Haslam 	else if (strcmp(p, "all") == 0)
257b9e93c10SJonathan Haslam 		flag |= CPC_COUNT_USER | CPC_COUNT_SYSTEM;
258b9e93c10SJonathan Haslam 	else
259b9e93c10SJonathan Haslam 		goto err;
260b9e93c10SJonathan Haslam 
261b9e93c10SJonathan Haslam 	/*
262b9e93c10SJonathan Haslam 	 * Next we either have a mask specification followed by an overflow
263b9e93c10SJonathan Haslam 	 * rate or just an overflow rate on its own.
264b9e93c10SJonathan Haslam 	 */
265b9e93c10SJonathan Haslam 	p += strlen(p) + 1;
266b9e93c10SJonathan Haslam 	if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
267b9e93c10SJonathan Haslam 		/*
268b9e93c10SJonathan Haslam 		 * A unit mask can only be specified if:
269b9e93c10SJonathan Haslam 		 * 1) this performance counter back end supports masks.
270b9e93c10SJonathan Haslam 		 * 2) the specified event is platform specific.
271b9e93c10SJonathan Haslam 		 * 3) a valid hex number is converted.
272b9e93c10SJonathan Haslam 		 * 4) no extraneous characters follow the mask specification.
273b9e93c10SJonathan Haslam 		 */
274b9e93c10SJonathan Haslam 		if (dcpc_mask_type != 0 && strncmp(event, "PAPI", 4) != 0 &&
275b9e93c10SJonathan Haslam 		    ddi_strtol(p, &end, 16, &umask) == 0 &&
276b9e93c10SJonathan Haslam 		    end == p + strlen(p)) {
277b9e93c10SJonathan Haslam 			p += strlen(p) + 1;
278b9e93c10SJonathan Haslam 		} else {
279b9e93c10SJonathan Haslam 			goto err;
280b9e93c10SJonathan Haslam 		}
281b9e93c10SJonathan Haslam 	}
282b9e93c10SJonathan Haslam 
283b9e93c10SJonathan Haslam 	/*
284b9e93c10SJonathan Haslam 	 * This final part must be an overflow value which has to be greater
285b9e93c10SJonathan Haslam 	 * than the minimum permissible overflow rate.
286b9e93c10SJonathan Haslam 	 */
287b9e93c10SJonathan Haslam 	if ((ddi_strtol(p, &end, 10, &val) != 0) || end != p + strlen(p) ||
288b9e93c10SJonathan Haslam 	    val < dcpc_min_overflow)
289b9e93c10SJonathan Haslam 		goto err;
290b9e93c10SJonathan Haslam 
291b9e93c10SJonathan Haslam 	/*
292b9e93c10SJonathan Haslam 	 * Validate the event and create the probe.
293b9e93c10SJonathan Haslam 	 */
294b9e93c10SJonathan Haslam 	for (i = 0; i < cpc_ncounters; i++) {
295*8cb74972SJonathan Haslam 		char *events, *cp, *p, *end;
296*8cb74972SJonathan Haslam 		int found = 0, j;
297*8cb74972SJonathan Haslam 		size_t llen;
298*8cb74972SJonathan Haslam 
299*8cb74972SJonathan Haslam 		if ((events = kcpc_list_events(i)) == NULL)
300*8cb74972SJonathan Haslam 			goto err;
301*8cb74972SJonathan Haslam 
302*8cb74972SJonathan Haslam 		llen = strlen(events);
303*8cb74972SJonathan Haslam 		p = cp = ddi_strdup(events, KM_NOSLEEP);
304*8cb74972SJonathan Haslam 		end = cp + llen;
305*8cb74972SJonathan Haslam 
306*8cb74972SJonathan Haslam 		for (j = 0; j < llen; j++) {
307*8cb74972SJonathan Haslam 			if (cp[j] == ',')
308*8cb74972SJonathan Haslam 				cp[j] = '\0';
309*8cb74972SJonathan Haslam 		}
310*8cb74972SJonathan Haslam 
311*8cb74972SJonathan Haslam 		while (p < end && found == 0) {
312*8cb74972SJonathan Haslam 			if (strcmp(p, event) == 0) {
313*8cb74972SJonathan Haslam 				dcpc_create_probe(dcpc_pid, desc->dtpd_name,
314*8cb74972SJonathan Haslam 				    event, umask, (uint32_t)val, flag);
315*8cb74972SJonathan Haslam 				found = 1;
316*8cb74972SJonathan Haslam 			}
317*8cb74972SJonathan Haslam 			p += strlen(p) + 1;
318*8cb74972SJonathan Haslam 		}
319*8cb74972SJonathan Haslam 		kmem_free(cp, llen + 1);
320*8cb74972SJonathan Haslam 
321*8cb74972SJonathan Haslam 		if (found)
322*8cb74972SJonathan Haslam 			break;
323b9e93c10SJonathan Haslam 	}
324b9e93c10SJonathan Haslam 
325b9e93c10SJonathan Haslam err:
326b9e93c10SJonathan Haslam 	kmem_free(str, len + 1);
327b9e93c10SJonathan Haslam }
328b9e93c10SJonathan Haslam 
329b9e93c10SJonathan Haslam /*ARGSUSED*/
330b9e93c10SJonathan Haslam static void
331b9e93c10SJonathan Haslam dcpc_destroy(void *arg, dtrace_id_t id, void *parg)
332b9e93c10SJonathan Haslam {
333b9e93c10SJonathan Haslam 	dcpc_probe_t *pp = parg;
334b9e93c10SJonathan Haslam 
335b9e93c10SJonathan Haslam 	ASSERT(pp->dcpc_enabled == 0);
336b9e93c10SJonathan Haslam 	kmem_free(pp, sizeof (dcpc_probe_t));
337b9e93c10SJonathan Haslam }
338b9e93c10SJonathan Haslam 
339b9e93c10SJonathan Haslam /*ARGSUSED*/
340b9e93c10SJonathan Haslam static int
341b9e93c10SJonathan Haslam dcpc_usermode(void *arg, dtrace_id_t id, void *parg)
342b9e93c10SJonathan Haslam {
343b9e93c10SJonathan Haslam 	return (CPU->cpu_cpcprofile_pc == 0);
344b9e93c10SJonathan Haslam }
345b9e93c10SJonathan Haslam 
346b9e93c10SJonathan Haslam static void
347b9e93c10SJonathan Haslam dcpc_populate_set(cpu_t *c, dcpc_probe_t *pp, kcpc_set_t *set, int reqno)
348b9e93c10SJonathan Haslam {
349b9e93c10SJonathan Haslam 	kcpc_set_t *oset;
350b9e93c10SJonathan Haslam 	int i;
351b9e93c10SJonathan Haslam 
352b9e93c10SJonathan Haslam 	(void) strncpy(set->ks_req[reqno].kr_event, pp->dcpc_event_name,
353b9e93c10SJonathan Haslam 	    CPC_MAX_EVENT_LEN);
354b9e93c10SJonathan Haslam 	set->ks_req[reqno].kr_config = NULL;
355b9e93c10SJonathan Haslam 	set->ks_req[reqno].kr_index = reqno;
356b9e93c10SJonathan Haslam 	set->ks_req[reqno].kr_picnum = -1;
357b9e93c10SJonathan Haslam 	set->ks_req[reqno].kr_flags =  pp->dcpc_flag;
358b9e93c10SJonathan Haslam 
359b9e93c10SJonathan Haslam 	/*
360b9e93c10SJonathan Haslam 	 * If a unit mask has been specified then detect which attribute
361b9e93c10SJonathan Haslam 	 * the platform needs. For now, it's either "umask" or "emask".
362b9e93c10SJonathan Haslam 	 */
363b9e93c10SJonathan Haslam 	if (pp->dcpc_umask >= 0) {
364b9e93c10SJonathan Haslam 		set->ks_req[reqno].kr_attr =
365b9e93c10SJonathan Haslam 		    kmem_zalloc(sizeof (kcpc_attr_t), KM_SLEEP);
366b9e93c10SJonathan Haslam 		set->ks_req[reqno].kr_nattrs = 1;
367b9e93c10SJonathan Haslam 		if (dcpc_mask_type & DCPC_UMASK)
368b9e93c10SJonathan Haslam 			(void) strncpy(set->ks_req[reqno].kr_attr->ka_name,
369b9e93c10SJonathan Haslam 			    "umask", 5);
370b9e93c10SJonathan Haslam 		else
371b9e93c10SJonathan Haslam 			(void) strncpy(set->ks_req[reqno].kr_attr->ka_name,
372b9e93c10SJonathan Haslam 			    "emask", 5);
373b9e93c10SJonathan Haslam 		set->ks_req[reqno].kr_attr->ka_val = pp->dcpc_umask;
374b9e93c10SJonathan Haslam 	} else {
375b9e93c10SJonathan Haslam 		set->ks_req[reqno].kr_attr = NULL;
376b9e93c10SJonathan Haslam 		set->ks_req[reqno].kr_nattrs = 0;
377b9e93c10SJonathan Haslam 	}
378b9e93c10SJonathan Haslam 
379b9e93c10SJonathan Haslam 	/*
380b9e93c10SJonathan Haslam 	 * If this probe is enabled, obtain its current countdown value
381b9e93c10SJonathan Haslam 	 * and use that. The CPUs cpc context might not exist yet if we
382b9e93c10SJonathan Haslam 	 * are dealing with a CPU that is just coming online.
383b9e93c10SJonathan Haslam 	 */
384b9e93c10SJonathan Haslam 	if (pp->dcpc_enabled && (c->cpu_cpc_ctx != NULL)) {
385b9e93c10SJonathan Haslam 		oset = c->cpu_cpc_ctx->kc_set;
386b9e93c10SJonathan Haslam 
387b9e93c10SJonathan Haslam 		for (i = 0; i < oset->ks_nreqs; i++) {
388b9e93c10SJonathan Haslam 			if (strcmp(oset->ks_req[i].kr_event,
389b9e93c10SJonathan Haslam 			    set->ks_req[reqno].kr_event) == 0) {
390b9e93c10SJonathan Haslam 				set->ks_req[reqno].kr_preset =
391b9e93c10SJonathan Haslam 				    *(oset->ks_req[i].kr_data);
392b9e93c10SJonathan Haslam 			}
393b9e93c10SJonathan Haslam 		}
394b9e93c10SJonathan Haslam 	} else {
395b9e93c10SJonathan Haslam 		set->ks_req[reqno].kr_preset = UINT64_MAX - pp->dcpc_ovfval;
396b9e93c10SJonathan Haslam 	}
397b9e93c10SJonathan Haslam 
398b9e93c10SJonathan Haslam 	set->ks_nreqs++;
399b9e93c10SJonathan Haslam }
400b9e93c10SJonathan Haslam 
401b9e93c10SJonathan Haslam 
402b9e93c10SJonathan Haslam /*
403b9e93c10SJonathan Haslam  * Create a fresh request set for the enablings represented in the
404b9e93c10SJonathan Haslam  * 'dcpc_actv_reqs' array which contains the probes we want to be
405b9e93c10SJonathan Haslam  * in the set. This can be called for several reasons:
406b9e93c10SJonathan Haslam  *
407b9e93c10SJonathan Haslam  * 1)	We are on a single or multi overflow platform and we have no
408b9e93c10SJonathan Haslam  *	current events so we can just create the set and initialize it.
409b9e93c10SJonathan Haslam  * 2)	We are on a multi-overflow platform and we already have one or
410b9e93c10SJonathan Haslam  *	more existing events and we are adding a new enabling. Create a
411b9e93c10SJonathan Haslam  *	new set and copy old requests in and then add the new request.
412b9e93c10SJonathan Haslam  * 3)	We are on a multi-overflow platform and we have just removed an
413b9e93c10SJonathan Haslam  *	enabling but we still have enablings whch are valid. Create a new
414b9e93c10SJonathan Haslam  *	set and copy in still valid requests.
415b9e93c10SJonathan Haslam  */
416b9e93c10SJonathan Haslam static kcpc_set_t *
417b9e93c10SJonathan Haslam dcpc_create_set(cpu_t *c)
418b9e93c10SJonathan Haslam {
419b9e93c10SJonathan Haslam 	int i, reqno = 0;
420b9e93c10SJonathan Haslam 	int active_requests = 0;
421b9e93c10SJonathan Haslam 	kcpc_set_t *set;
422b9e93c10SJonathan Haslam 
423b9e93c10SJonathan Haslam 	/*
424b9e93c10SJonathan Haslam 	 * First get a count of the number of currently active requests.
425b9e93c10SJonathan Haslam 	 * Note that dcpc_actv_reqs[] should always reflect which requests
426b9e93c10SJonathan Haslam 	 * we want to be in the set that is to be created. It is the
427b9e93c10SJonathan Haslam 	 * responsibility of the caller of dcpc_create_set() to adjust that
428b9e93c10SJonathan Haslam 	 * array accordingly beforehand.
429b9e93c10SJonathan Haslam 	 */
430b9e93c10SJonathan Haslam 	for (i = 0; i < cpc_ncounters; i++) {
431b9e93c10SJonathan Haslam 		if (dcpc_actv_reqs[i] != NULL)
432b9e93c10SJonathan Haslam 			active_requests++;
433b9e93c10SJonathan Haslam 	}
434b9e93c10SJonathan Haslam 
435b9e93c10SJonathan Haslam 	set = kmem_zalloc(sizeof (kcpc_set_t), KM_SLEEP);
436b9e93c10SJonathan Haslam 
437b9e93c10SJonathan Haslam 	set->ks_req =
438b9e93c10SJonathan Haslam 	    kmem_zalloc(sizeof (kcpc_request_t) * active_requests, KM_SLEEP);
439b9e93c10SJonathan Haslam 
440b9e93c10SJonathan Haslam 	set->ks_data =
441b9e93c10SJonathan Haslam 	    kmem_zalloc(active_requests * sizeof (uint64_t), KM_SLEEP);
442b9e93c10SJonathan Haslam 
443b9e93c10SJonathan Haslam 	/*
444b9e93c10SJonathan Haslam 	 * Look for valid entries in the active requests array and populate
445b9e93c10SJonathan Haslam 	 * the request set for any entries found.
446b9e93c10SJonathan Haslam 	 */
447b9e93c10SJonathan Haslam 	for (i = 0; i < cpc_ncounters; i++) {
448b9e93c10SJonathan Haslam 		if (dcpc_actv_reqs[i] != NULL) {
449b9e93c10SJonathan Haslam 			dcpc_populate_set(c, dcpc_actv_reqs[i], set, reqno);
450b9e93c10SJonathan Haslam 			reqno++;
451b9e93c10SJonathan Haslam 		}
452b9e93c10SJonathan Haslam 	}
453b9e93c10SJonathan Haslam 
454b9e93c10SJonathan Haslam 	return (set);
455b9e93c10SJonathan Haslam }
456b9e93c10SJonathan Haslam 
457b9e93c10SJonathan Haslam static int
458b9e93c10SJonathan Haslam dcpc_program_cpu_event(cpu_t *c)
459b9e93c10SJonathan Haslam {
460b9e93c10SJonathan Haslam 	int i, j, subcode;
461b9e93c10SJonathan Haslam 	kcpc_ctx_t *ctx, *octx;
462b9e93c10SJonathan Haslam 	kcpc_set_t *set;
463b9e93c10SJonathan Haslam 
464b9e93c10SJonathan Haslam 	set = dcpc_create_set(c);
465b9e93c10SJonathan Haslam 
466b9e93c10SJonathan Haslam 	octx = NULL;
467b9e93c10SJonathan Haslam 	set->ks_ctx = ctx = kcpc_ctx_alloc();
468b9e93c10SJonathan Haslam 	ctx->kc_set = set;
469b9e93c10SJonathan Haslam 	ctx->kc_cpuid = c->cpu_id;
470b9e93c10SJonathan Haslam 
471b9e93c10SJonathan Haslam 	if (kcpc_assign_reqs(set, ctx) != 0)
472b9e93c10SJonathan Haslam 		goto err;
473b9e93c10SJonathan Haslam 
474b9e93c10SJonathan Haslam 	if (kcpc_configure_reqs(ctx, set, &subcode) != 0)
475b9e93c10SJonathan Haslam 		goto err;
476b9e93c10SJonathan Haslam 
477b9e93c10SJonathan Haslam 	for (i = 0; i < set->ks_nreqs; i++) {
478b9e93c10SJonathan Haslam 		for (j = 0; j < cpc_ncounters; j++) {
479b9e93c10SJonathan Haslam 			if (dcpc_actv_reqs[j] != NULL &&
480b9e93c10SJonathan Haslam 			    strcmp(set->ks_req[i].kr_event,
481b9e93c10SJonathan Haslam 			    dcpc_actv_reqs[j]->dcpc_event_name) == 0) {
482b9e93c10SJonathan Haslam 				dcpc_actv_reqs[j]->dcpc_picno =
483b9e93c10SJonathan Haslam 				    set->ks_req[i].kr_picnum;
484b9e93c10SJonathan Haslam 			}
485b9e93c10SJonathan Haslam 		}
486b9e93c10SJonathan Haslam 	}
487b9e93c10SJonathan Haslam 
488b9e93c10SJonathan Haslam 	/*
489b9e93c10SJonathan Haslam 	 * If we already have an active enabling then save the current cpc
490b9e93c10SJonathan Haslam 	 * context away.
491b9e93c10SJonathan Haslam 	 */
492b9e93c10SJonathan Haslam 	if (c->cpu_cpc_ctx != NULL)
493b9e93c10SJonathan Haslam 		octx = c->cpu_cpc_ctx;
494b9e93c10SJonathan Haslam 
495b9e93c10SJonathan Haslam 	c->cpu_cpc_ctx = ctx;
496b9e93c10SJonathan Haslam 	kcpc_remote_program(c);
497b9e93c10SJonathan Haslam 
498b9e93c10SJonathan Haslam 	if (octx != NULL) {
499b9e93c10SJonathan Haslam 		kcpc_set_t *oset = octx->kc_set;
500b9e93c10SJonathan Haslam 		kmem_free(oset->ks_data, oset->ks_nreqs * sizeof (uint64_t));
501b9e93c10SJonathan Haslam 		kcpc_free_set(oset);
502b9e93c10SJonathan Haslam 		kcpc_ctx_free(octx);
503b9e93c10SJonathan Haslam 	}
504b9e93c10SJonathan Haslam 
505b9e93c10SJonathan Haslam 	return (0);
506b9e93c10SJonathan Haslam 
507b9e93c10SJonathan Haslam err:
508b9e93c10SJonathan Haslam 	/*
509b9e93c10SJonathan Haslam 	 * We failed to configure this request up so free things up and
510b9e93c10SJonathan Haslam 	 * get out.
511b9e93c10SJonathan Haslam 	 */
512b9e93c10SJonathan Haslam 	kmem_free(set->ks_data, set->ks_nreqs * sizeof (uint64_t));
513b9e93c10SJonathan Haslam 	kcpc_free_set(set);
514b9e93c10SJonathan Haslam 	kcpc_ctx_free(ctx);
515b9e93c10SJonathan Haslam 
516b9e93c10SJonathan Haslam 	return (-1);
517b9e93c10SJonathan Haslam }
518b9e93c10SJonathan Haslam 
519b9e93c10SJonathan Haslam static void
520b9e93c10SJonathan Haslam dcpc_disable_cpu(cpu_t *c)
521b9e93c10SJonathan Haslam {
522b9e93c10SJonathan Haslam 	kcpc_ctx_t *ctx;
523b9e93c10SJonathan Haslam 	kcpc_set_t *set;
524b9e93c10SJonathan Haslam 
525b9e93c10SJonathan Haslam 	/*
526b9e93c10SJonathan Haslam 	 * Leave this CPU alone if it's already offline.
527b9e93c10SJonathan Haslam 	 */
528b9e93c10SJonathan Haslam 	if (c->cpu_flags & CPU_OFFLINE)
529b9e93c10SJonathan Haslam 		return;
530b9e93c10SJonathan Haslam 
531b9e93c10SJonathan Haslam 	kcpc_remote_stop(c);
532b9e93c10SJonathan Haslam 
533b9e93c10SJonathan Haslam 	ctx = c->cpu_cpc_ctx;
534b9e93c10SJonathan Haslam 	set = ctx->kc_set;
535b9e93c10SJonathan Haslam 
536b9e93c10SJonathan Haslam 	kcpc_free_configs(set);
537b9e93c10SJonathan Haslam 
538b9e93c10SJonathan Haslam 	kmem_free(set->ks_data, set->ks_nreqs * sizeof (uint64_t));
539b9e93c10SJonathan Haslam 	kcpc_free_set(set);
540b9e93c10SJonathan Haslam 	kcpc_ctx_free(ctx);
541b9e93c10SJonathan Haslam 	c->cpu_cpc_ctx = NULL;
542b9e93c10SJonathan Haslam }
543b9e93c10SJonathan Haslam 
544b9e93c10SJonathan Haslam /*
545b9e93c10SJonathan Haslam  * Stop overflow interrupts being actively processed so that per-CPU
546b9e93c10SJonathan Haslam  * configuration state can be changed safely and correctly. Each CPU has a
547b9e93c10SJonathan Haslam  * dcpc interrupt state byte which is transitioned from DCPC_INTR_FREE (the
548b9e93c10SJonathan Haslam  * "free" state) to DCPC_INTR_CONFIG (the "configuration in process" state)
549b9e93c10SJonathan Haslam  * before any configuration state is changed on any CPUs. The hardware overflow
550b9e93c10SJonathan Haslam  * handler, kcpc_hw_overflow_intr(), will only process an interrupt when a
551b9e93c10SJonathan Haslam  * configuration is not in process (i.e. the state is marked as free). During
552b9e93c10SJonathan Haslam  * interrupt processing the state is set to DCPC_INTR_PROCESSING by the
553b9e93c10SJonathan Haslam  * overflow handler.
554b9e93c10SJonathan Haslam  */
555b9e93c10SJonathan Haslam static void
556b9e93c10SJonathan Haslam dcpc_block_interrupts(void)
557b9e93c10SJonathan Haslam {
558b9e93c10SJonathan Haslam 	cpu_t *c;
559b9e93c10SJonathan Haslam 	uint8_t *state;
560b9e93c10SJonathan Haslam 
561b9e93c10SJonathan Haslam 	c = cpu_list;
562b9e93c10SJonathan Haslam 
563b9e93c10SJonathan Haslam 	do {
564b9e93c10SJonathan Haslam 		state = &cpu_core[c->cpu_id].cpuc_dcpc_intr_state;
565b9e93c10SJonathan Haslam 
566b9e93c10SJonathan Haslam 		while (atomic_cas_8(state, DCPC_INTR_FREE,
567b9e93c10SJonathan Haslam 		    DCPC_INTR_CONFIG) != DCPC_INTR_FREE)
568b9e93c10SJonathan Haslam 			continue;
569b9e93c10SJonathan Haslam 
570b9e93c10SJonathan Haslam 	} while ((c = c->cpu_next) != cpu_list);
571b9e93c10SJonathan Haslam }
572b9e93c10SJonathan Haslam 
573b9e93c10SJonathan Haslam /*
574b9e93c10SJonathan Haslam  * Set all CPUs dcpc interrupt state to DCPC_INTR_FREE to indicate that
575b9e93c10SJonathan Haslam  * overflow interrupts can be processed safely.
576b9e93c10SJonathan Haslam  */
577b9e93c10SJonathan Haslam static void
578b9e93c10SJonathan Haslam dcpc_release_interrupts(void)
579b9e93c10SJonathan Haslam {
580b9e93c10SJonathan Haslam 	cpu_t *c = cpu_list;
581b9e93c10SJonathan Haslam 
582b9e93c10SJonathan Haslam 	do {
583b9e93c10SJonathan Haslam 		cpu_core[c->cpu_id].cpuc_dcpc_intr_state = DCPC_INTR_FREE;
584b9e93c10SJonathan Haslam 		membar_producer();
585b9e93c10SJonathan Haslam 	} while ((c = c->cpu_next) != cpu_list);
586b9e93c10SJonathan Haslam }
587b9e93c10SJonathan Haslam 
588b9e93c10SJonathan Haslam /*
589b9e93c10SJonathan Haslam  * dcpc_program_event() can be called owing to a new enabling or if a multi
590b9e93c10SJonathan Haslam  * overflow platform has disabled a request but needs to  program the requests
591b9e93c10SJonathan Haslam  * that are still valid.
592b9e93c10SJonathan Haslam  *
593b9e93c10SJonathan Haslam  * Every invocation of dcpc_program_event() will create a new kcpc_ctx_t
594b9e93c10SJonathan Haslam  * and a new request set which contains the new enabling and any old enablings
595b9e93c10SJonathan Haslam  * which are still valid (possible with multi-overflow platforms).
596b9e93c10SJonathan Haslam  */
597b9e93c10SJonathan Haslam static int
598b9e93c10SJonathan Haslam dcpc_program_event(dcpc_probe_t *pp)
599b9e93c10SJonathan Haslam {
600b9e93c10SJonathan Haslam 	cpu_t *c;
601b9e93c10SJonathan Haslam 	int ret = 0;
602b9e93c10SJonathan Haslam 
603b9e93c10SJonathan Haslam 	ASSERT(MUTEX_HELD(&cpu_lock));
604b9e93c10SJonathan Haslam 
605b9e93c10SJonathan Haslam 	kpreempt_disable();
606b9e93c10SJonathan Haslam 
607b9e93c10SJonathan Haslam 	dcpc_block_interrupts();
608b9e93c10SJonathan Haslam 
609b9e93c10SJonathan Haslam 	c = cpu_list;
610b9e93c10SJonathan Haslam 
611b9e93c10SJonathan Haslam 	do {
612b9e93c10SJonathan Haslam 		/*
613b9e93c10SJonathan Haslam 		 * Skip CPUs that are currently offline.
614b9e93c10SJonathan Haslam 		 */
615b9e93c10SJonathan Haslam 		if (c->cpu_flags & CPU_OFFLINE)
616b9e93c10SJonathan Haslam 			continue;
617b9e93c10SJonathan Haslam 
618b9e93c10SJonathan Haslam 		if (c->cpu_cpc_ctx != NULL)
619b9e93c10SJonathan Haslam 			kcpc_remote_stop(c);
620b9e93c10SJonathan Haslam 	} while ((c = c->cpu_next) != cpu_list);
621b9e93c10SJonathan Haslam 
622b9e93c10SJonathan Haslam 	dcpc_release_interrupts();
623b9e93c10SJonathan Haslam 
624b9e93c10SJonathan Haslam 	/*
625b9e93c10SJonathan Haslam 	 * If this enabling is being removed (in the case of a multi event
626b9e93c10SJonathan Haslam 	 * capable system with more than one active enabling), we can now
627b9e93c10SJonathan Haslam 	 * update the active request array to reflect the enablings that need
628b9e93c10SJonathan Haslam 	 * to be reprogrammed.
629b9e93c10SJonathan Haslam 	 */
630b9e93c10SJonathan Haslam 	if (pp->dcpc_disabling == 1)
631b9e93c10SJonathan Haslam 		dcpc_actv_reqs[pp->dcpc_actv_req_idx] = NULL;
632b9e93c10SJonathan Haslam 
633b9e93c10SJonathan Haslam 	do {
634b9e93c10SJonathan Haslam 		/*
635b9e93c10SJonathan Haslam 		 * Skip CPUs that are currently offline.
636b9e93c10SJonathan Haslam 		 */
637b9e93c10SJonathan Haslam 		if (c->cpu_flags & CPU_OFFLINE)
638b9e93c10SJonathan Haslam 			continue;
639b9e93c10SJonathan Haslam 
640b9e93c10SJonathan Haslam 		ret = dcpc_program_cpu_event(c);
641b9e93c10SJonathan Haslam 	} while ((c = c->cpu_next) != cpu_list && ret == 0);
642b9e93c10SJonathan Haslam 
643b9e93c10SJonathan Haslam 	/*
644b9e93c10SJonathan Haslam 	 * If dcpc_program_cpu_event() fails then it is because we couldn't
645b9e93c10SJonathan Haslam 	 * configure the requests in the set for the CPU and not because of
646b9e93c10SJonathan Haslam 	 * an error programming the hardware. If we have a failure here then
647b9e93c10SJonathan Haslam 	 * we assume no CPUs have been programmed in the above step as they
648b9e93c10SJonathan Haslam 	 * are all configured identically.
649b9e93c10SJonathan Haslam 	 */
650b9e93c10SJonathan Haslam 	if (ret != 0) {
651b9e93c10SJonathan Haslam 		pp->dcpc_enabled = 0;
652b9e93c10SJonathan Haslam 		kpreempt_enable();
653b9e93c10SJonathan Haslam 		return (-1);
654b9e93c10SJonathan Haslam 	}
655b9e93c10SJonathan Haslam 
656b9e93c10SJonathan Haslam 	if (pp->dcpc_disabling != 1)
657b9e93c10SJonathan Haslam 		pp->dcpc_enabled = 1;
658b9e93c10SJonathan Haslam 
659b9e93c10SJonathan Haslam 	kpreempt_enable();
660b9e93c10SJonathan Haslam 
661b9e93c10SJonathan Haslam 	return (0);
662b9e93c10SJonathan Haslam }
663b9e93c10SJonathan Haslam 
664b9e93c10SJonathan Haslam /*ARGSUSED*/
665b9e93c10SJonathan Haslam static int
666b9e93c10SJonathan Haslam dcpc_enable(void *arg, dtrace_id_t id, void *parg)
667b9e93c10SJonathan Haslam {
668b9e93c10SJonathan Haslam 	dcpc_probe_t *pp = parg;
669b9e93c10SJonathan Haslam 	int i, found = 0;
670b9e93c10SJonathan Haslam 	cpu_t *c;
671b9e93c10SJonathan Haslam 
672b9e93c10SJonathan Haslam 	ASSERT(MUTEX_HELD(&cpu_lock));
673b9e93c10SJonathan Haslam 
674b9e93c10SJonathan Haslam 	/*
675b9e93c10SJonathan Haslam 	 * Bail out if the counters are being used by a libcpc consumer.
676b9e93c10SJonathan Haslam 	 */
677b9e93c10SJonathan Haslam 	rw_enter(&kcpc_cpuctx_lock, RW_READER);
678b9e93c10SJonathan Haslam 	if (kcpc_cpuctx > 0) {
679b9e93c10SJonathan Haslam 		rw_exit(&kcpc_cpuctx_lock);
680b9e93c10SJonathan Haslam 		return (-1);
681b9e93c10SJonathan Haslam 	}
682b9e93c10SJonathan Haslam 
683b9e93c10SJonathan Haslam 	dtrace_cpc_in_use++;
684b9e93c10SJonathan Haslam 	rw_exit(&kcpc_cpuctx_lock);
685b9e93c10SJonathan Haslam 
686b9e93c10SJonathan Haslam 	/*
687b9e93c10SJonathan Haslam 	 * Locate this enabling in the first free entry of the active
688b9e93c10SJonathan Haslam 	 * request array.
689b9e93c10SJonathan Haslam 	 */
690b9e93c10SJonathan Haslam 	for (i = 0; i < cpc_ncounters; i++) {
691b9e93c10SJonathan Haslam 		if (dcpc_actv_reqs[i] == NULL) {
692b9e93c10SJonathan Haslam 			dcpc_actv_reqs[i] = pp;
693b9e93c10SJonathan Haslam 			pp->dcpc_actv_req_idx = i;
694b9e93c10SJonathan Haslam 			found = 1;
695b9e93c10SJonathan Haslam 			break;
696b9e93c10SJonathan Haslam 		}
697b9e93c10SJonathan Haslam 	}
698b9e93c10SJonathan Haslam 
699b9e93c10SJonathan Haslam 	/*
700b9e93c10SJonathan Haslam 	 * If we couldn't find a slot for this probe then there is no
701b9e93c10SJonathan Haslam 	 * room at the inn.
702b9e93c10SJonathan Haslam 	 */
703b9e93c10SJonathan Haslam 	if (!found) {
704b9e93c10SJonathan Haslam 		dtrace_cpc_in_use--;
705b9e93c10SJonathan Haslam 		return (-1);
706b9e93c10SJonathan Haslam 	}
707b9e93c10SJonathan Haslam 
708b9e93c10SJonathan Haslam 	ASSERT(pp->dcpc_actv_req_idx >= 0);
709b9e93c10SJonathan Haslam 
710b9e93c10SJonathan Haslam 	/*
711b9e93c10SJonathan Haslam 	 * The following must hold true if we are to (attempt to) enable
712b9e93c10SJonathan Haslam 	 * this request:
713b9e93c10SJonathan Haslam 	 *
714b9e93c10SJonathan Haslam 	 * 1) No enablings currently exist. We allow all platforms to
715b9e93c10SJonathan Haslam 	 * proceed if this is true.
716b9e93c10SJonathan Haslam 	 *
717b9e93c10SJonathan Haslam 	 * OR
718b9e93c10SJonathan Haslam 	 *
719b9e93c10SJonathan Haslam 	 * 2) If the platform is multi overflow capable and there are
720b9e93c10SJonathan Haslam 	 * less valid enablings than there are counters. There is no
721b9e93c10SJonathan Haslam 	 * guarantee that a platform can accommodate as many events as
722b9e93c10SJonathan Haslam 	 * it has counters for but we will at least try to program
723b9e93c10SJonathan Haslam 	 * up to that many requests.
724b9e93c10SJonathan Haslam 	 *
725b9e93c10SJonathan Haslam 	 * The 'dcpc_enablings' variable is implictly protected by locking
726b9e93c10SJonathan Haslam 	 * provided by the DTrace framework and the cpu management framework.
727b9e93c10SJonathan Haslam 	 */
728b9e93c10SJonathan Haslam 	if (dcpc_enablings == 0 || (dcpc_mult_ovf_cap &&
729b9e93c10SJonathan Haslam 	    dcpc_enablings < cpc_ncounters)) {
730b9e93c10SJonathan Haslam 		/*
731b9e93c10SJonathan Haslam 		 * Before attempting to program the first enabling we need to
732b9e93c10SJonathan Haslam 		 * invalidate any lwp-based contexts.
733b9e93c10SJonathan Haslam 		 */
734b9e93c10SJonathan Haslam 		if (dcpc_enablings == 0)
735b9e93c10SJonathan Haslam 			kcpc_invalidate_all();
736b9e93c10SJonathan Haslam 
737b9e93c10SJonathan Haslam 		if (dcpc_program_event(pp) == 0) {
738b9e93c10SJonathan Haslam 			dcpc_enablings++;
739b9e93c10SJonathan Haslam 			return (0);
740b9e93c10SJonathan Haslam 		}
741b9e93c10SJonathan Haslam 	}
742b9e93c10SJonathan Haslam 
743b9e93c10SJonathan Haslam 	/*
744b9e93c10SJonathan Haslam 	 * If active enablings existed before we failed to enable this probe
745b9e93c10SJonathan Haslam 	 * on a multi event capable platform then we need to restart counters
746b9e93c10SJonathan Haslam 	 * as they will have been stopped in the attempted configuration. The
747b9e93c10SJonathan Haslam 	 * context should now just contain the request prior to this failed
748b9e93c10SJonathan Haslam 	 * enabling.
749b9e93c10SJonathan Haslam 	 */
750b9e93c10SJonathan Haslam 	if (dcpc_enablings > 0 && dcpc_mult_ovf_cap) {
751b9e93c10SJonathan Haslam 		c = cpu_list;
752b9e93c10SJonathan Haslam 
753b9e93c10SJonathan Haslam 		ASSERT(dcpc_mult_ovf_cap == 1);
754b9e93c10SJonathan Haslam 		do {
755b9e93c10SJonathan Haslam 			/*
756b9e93c10SJonathan Haslam 			 * Skip CPUs that are currently offline.
757b9e93c10SJonathan Haslam 			 */
758b9e93c10SJonathan Haslam 			if (c->cpu_flags & CPU_OFFLINE)
759b9e93c10SJonathan Haslam 				continue;
760b9e93c10SJonathan Haslam 
761b9e93c10SJonathan Haslam 			kcpc_remote_program(c);
762b9e93c10SJonathan Haslam 		} while ((c = c->cpu_next) != cpu_list);
763b9e93c10SJonathan Haslam 	}
764b9e93c10SJonathan Haslam 
765b9e93c10SJonathan Haslam 	dtrace_cpc_in_use--;
766b9e93c10SJonathan Haslam 	dcpc_actv_reqs[pp->dcpc_actv_req_idx] = NULL;
767b9e93c10SJonathan Haslam 	pp->dcpc_actv_req_idx = pp->dcpc_picno = -1;
768b9e93c10SJonathan Haslam 
769b9e93c10SJonathan Haslam 	return (-1);
770b9e93c10SJonathan Haslam }
771b9e93c10SJonathan Haslam 
772b9e93c10SJonathan Haslam /*
773b9e93c10SJonathan Haslam  * If only one enabling is active then remove the context and free
774b9e93c10SJonathan Haslam  * everything up. If there are multiple enablings active then remove this
775b9e93c10SJonathan Haslam  * one, its associated meta-data and re-program the hardware.
776b9e93c10SJonathan Haslam  */
777b9e93c10SJonathan Haslam /*ARGSUSED*/
778b9e93c10SJonathan Haslam static void
779b9e93c10SJonathan Haslam dcpc_disable(void *arg, dtrace_id_t id, void *parg)
780b9e93c10SJonathan Haslam {
781b9e93c10SJonathan Haslam 	cpu_t *c;
782b9e93c10SJonathan Haslam 	dcpc_probe_t *pp = parg;
783b9e93c10SJonathan Haslam 
784b9e93c10SJonathan Haslam 	ASSERT(MUTEX_HELD(&cpu_lock));
785b9e93c10SJonathan Haslam 
786b9e93c10SJonathan Haslam 	kpreempt_disable();
787b9e93c10SJonathan Haslam 
788b9e93c10SJonathan Haslam 	/*
789b9e93c10SJonathan Haslam 	 * This probe didn't actually make it as far as being fully enabled
790b9e93c10SJonathan Haslam 	 * so we needn't do anything with it.
791b9e93c10SJonathan Haslam 	 */
792b9e93c10SJonathan Haslam 	if (pp->dcpc_enabled == 0) {
793b9e93c10SJonathan Haslam 		/*
794b9e93c10SJonathan Haslam 		 * If we actually allocated this request a slot in the
795b9e93c10SJonathan Haslam 		 * request array but failed to enabled it then remove the
796b9e93c10SJonathan Haslam 		 * entry in the array.
797b9e93c10SJonathan Haslam 		 */
798b9e93c10SJonathan Haslam 		if (pp->dcpc_actv_req_idx >= 0) {
799b9e93c10SJonathan Haslam 			dcpc_actv_reqs[pp->dcpc_actv_req_idx] = NULL;
800b9e93c10SJonathan Haslam 			pp->dcpc_actv_req_idx = pp->dcpc_picno =
801b9e93c10SJonathan Haslam 			    pp->dcpc_disabling = -1;
802b9e93c10SJonathan Haslam 		}
803b9e93c10SJonathan Haslam 
804b9e93c10SJonathan Haslam 		kpreempt_enable();
805b9e93c10SJonathan Haslam 		return;
806b9e93c10SJonathan Haslam 	}
807b9e93c10SJonathan Haslam 
808b9e93c10SJonathan Haslam 	/*
809b9e93c10SJonathan Haslam 	 * If this is the only enabling then stop all the counters and
810b9e93c10SJonathan Haslam 	 * free up the meta-data.
811b9e93c10SJonathan Haslam 	 */
812b9e93c10SJonathan Haslam 	if (dcpc_enablings == 1) {
813b9e93c10SJonathan Haslam 		ASSERT(dtrace_cpc_in_use == 1);
814b9e93c10SJonathan Haslam 
815b9e93c10SJonathan Haslam 		dcpc_block_interrupts();
816b9e93c10SJonathan Haslam 
817b9e93c10SJonathan Haslam 		c = cpu_list;
818b9e93c10SJonathan Haslam 
819b9e93c10SJonathan Haslam 		do {
820b9e93c10SJonathan Haslam 			dcpc_disable_cpu(c);
821b9e93c10SJonathan Haslam 		} while ((c = c->cpu_next) != cpu_list);
822b9e93c10SJonathan Haslam 
823b9e93c10SJonathan Haslam 		dcpc_actv_reqs[pp->dcpc_actv_req_idx] = NULL;
824b9e93c10SJonathan Haslam 		dcpc_release_interrupts();
825b9e93c10SJonathan Haslam 	} else {
826b9e93c10SJonathan Haslam 		/*
827b9e93c10SJonathan Haslam 		 * This platform can support multiple overflow events and
828b9e93c10SJonathan Haslam 		 * the enabling being disabled is not the last one. Remove this
829b9e93c10SJonathan Haslam 		 * enabling and re-program the hardware with the new config.
830b9e93c10SJonathan Haslam 		 */
831b9e93c10SJonathan Haslam 		ASSERT(dcpc_mult_ovf_cap);
832b9e93c10SJonathan Haslam 		ASSERT(dcpc_enablings > 1);
833b9e93c10SJonathan Haslam 
834b9e93c10SJonathan Haslam 		pp->dcpc_disabling = 1;
835b9e93c10SJonathan Haslam 		(void) dcpc_program_event(pp);
836b9e93c10SJonathan Haslam 	}
837b9e93c10SJonathan Haslam 
838b9e93c10SJonathan Haslam 	kpreempt_enable();
839b9e93c10SJonathan Haslam 
840b9e93c10SJonathan Haslam 	dcpc_enablings--;
841b9e93c10SJonathan Haslam 	dtrace_cpc_in_use--;
842b9e93c10SJonathan Haslam 	pp->dcpc_enabled = 0;
843b9e93c10SJonathan Haslam 	pp->dcpc_actv_req_idx = pp->dcpc_picno = pp->dcpc_disabling = -1;
844b9e93c10SJonathan Haslam }
845b9e93c10SJonathan Haslam 
846b9e93c10SJonathan Haslam /*ARGSUSED*/
847b9e93c10SJonathan Haslam static int
848b9e93c10SJonathan Haslam dcpc_cpu_setup(cpu_setup_t what, processorid_t cpu, void *arg)
849b9e93c10SJonathan Haslam {
850b9e93c10SJonathan Haslam 	cpu_t *c;
851b9e93c10SJonathan Haslam 	uint8_t *state;
852b9e93c10SJonathan Haslam 
853b9e93c10SJonathan Haslam 	ASSERT(MUTEX_HELD(&cpu_lock));
854b9e93c10SJonathan Haslam 
855b9e93c10SJonathan Haslam 	switch (what) {
856b9e93c10SJonathan Haslam 	case CPU_OFF:
857b9e93c10SJonathan Haslam 		/*
858b9e93c10SJonathan Haslam 		 * Offline CPUs are not allowed to take part so remove this
859b9e93c10SJonathan Haslam 		 * CPU if we are actively tracing.
860b9e93c10SJonathan Haslam 		 */
861b9e93c10SJonathan Haslam 		if (dtrace_cpc_in_use) {
862b9e93c10SJonathan Haslam 			c = cpu_get(cpu);
863b9e93c10SJonathan Haslam 			state = &cpu_core[c->cpu_id].cpuc_dcpc_intr_state;
864b9e93c10SJonathan Haslam 
865b9e93c10SJonathan Haslam 			/*
866b9e93c10SJonathan Haslam 			 * Indicate that a configuration is in process in
867b9e93c10SJonathan Haslam 			 * order to stop overflow interrupts being processed
868b9e93c10SJonathan Haslam 			 * on this CPU while we disable it.
869b9e93c10SJonathan Haslam 			 */
870b9e93c10SJonathan Haslam 			while (atomic_cas_8(state, DCPC_INTR_FREE,
871b9e93c10SJonathan Haslam 			    DCPC_INTR_CONFIG) != DCPC_INTR_FREE)
872b9e93c10SJonathan Haslam 				continue;
873b9e93c10SJonathan Haslam 
874b9e93c10SJonathan Haslam 			dcpc_disable_cpu(c);
875b9e93c10SJonathan Haslam 
876b9e93c10SJonathan Haslam 			/*
877b9e93c10SJonathan Haslam 			 * Reset this CPUs interrupt state as the configuration
878b9e93c10SJonathan Haslam 			 * has ended.
879b9e93c10SJonathan Haslam 			 */
880b9e93c10SJonathan Haslam 			cpu_core[c->cpu_id].cpuc_dcpc_intr_state =
881b9e93c10SJonathan Haslam 			    DCPC_INTR_FREE;
882b9e93c10SJonathan Haslam 			membar_producer();
883b9e93c10SJonathan Haslam 		}
884b9e93c10SJonathan Haslam 		break;
885b9e93c10SJonathan Haslam 
886b9e93c10SJonathan Haslam 	case CPU_ON:
887b9e93c10SJonathan Haslam 	case CPU_SETUP:
888b9e93c10SJonathan Haslam 		/*
889b9e93c10SJonathan Haslam 		 * This CPU is being initialized or brought online so program
890b9e93c10SJonathan Haslam 		 * it with the current request set if we are actively tracing.
891b9e93c10SJonathan Haslam 		 */
892b9e93c10SJonathan Haslam 		if (dtrace_cpc_in_use) {
893b9e93c10SJonathan Haslam 			c = cpu_get(cpu);
894b9e93c10SJonathan Haslam 
895b9e93c10SJonathan Haslam 			(void) dcpc_program_cpu_event(c);
896b9e93c10SJonathan Haslam 		}
897b9e93c10SJonathan Haslam 		break;
898b9e93c10SJonathan Haslam 
899b9e93c10SJonathan Haslam 	default:
900b9e93c10SJonathan Haslam 		break;
901b9e93c10SJonathan Haslam 	}
902b9e93c10SJonathan Haslam 
903b9e93c10SJonathan Haslam 	return (0);
904b9e93c10SJonathan Haslam }
905b9e93c10SJonathan Haslam 
906b9e93c10SJonathan Haslam static dtrace_pattr_t dcpc_attr = {
907b9e93c10SJonathan Haslam { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
908b9e93c10SJonathan Haslam { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
909b9e93c10SJonathan Haslam { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
910b9e93c10SJonathan Haslam { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_CPU },
911b9e93c10SJonathan Haslam { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
912b9e93c10SJonathan Haslam };
913b9e93c10SJonathan Haslam 
914b9e93c10SJonathan Haslam static dtrace_pops_t dcpc_pops = {
915b9e93c10SJonathan Haslam     dcpc_provide,
916b9e93c10SJonathan Haslam     NULL,
917b9e93c10SJonathan Haslam     dcpc_enable,
918b9e93c10SJonathan Haslam     dcpc_disable,
919b9e93c10SJonathan Haslam     NULL,
920b9e93c10SJonathan Haslam     NULL,
921b9e93c10SJonathan Haslam     NULL,
922b9e93c10SJonathan Haslam     NULL,
923b9e93c10SJonathan Haslam     dcpc_usermode,
924b9e93c10SJonathan Haslam     dcpc_destroy
925b9e93c10SJonathan Haslam };
926b9e93c10SJonathan Haslam 
927b9e93c10SJonathan Haslam /*ARGSUSED*/
928b9e93c10SJonathan Haslam static int
929b9e93c10SJonathan Haslam dcpc_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
930b9e93c10SJonathan Haslam {
931b9e93c10SJonathan Haslam 	return (0);
932b9e93c10SJonathan Haslam }
933b9e93c10SJonathan Haslam 
934b9e93c10SJonathan Haslam /*ARGSUSED*/
935b9e93c10SJonathan Haslam static int
936b9e93c10SJonathan Haslam dcpc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
937b9e93c10SJonathan Haslam {
938b9e93c10SJonathan Haslam 	int error;
939b9e93c10SJonathan Haslam 
940b9e93c10SJonathan Haslam 	switch (infocmd) {
941b9e93c10SJonathan Haslam 	case DDI_INFO_DEVT2DEVINFO:
942b9e93c10SJonathan Haslam 		*result = (void *)dcpc_devi;
943b9e93c10SJonathan Haslam 		error = DDI_SUCCESS;
944b9e93c10SJonathan Haslam 		break;
945b9e93c10SJonathan Haslam 	case DDI_INFO_DEVT2INSTANCE:
946b9e93c10SJonathan Haslam 		*result = (void *)0;
947b9e93c10SJonathan Haslam 		error = DDI_SUCCESS;
948b9e93c10SJonathan Haslam 		break;
949b9e93c10SJonathan Haslam 	default:
950b9e93c10SJonathan Haslam 		error = DDI_FAILURE;
951b9e93c10SJonathan Haslam 	}
952b9e93c10SJonathan Haslam 	return (error);
953b9e93c10SJonathan Haslam }
954b9e93c10SJonathan Haslam 
955b9e93c10SJonathan Haslam static int
956b9e93c10SJonathan Haslam dcpc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
957b9e93c10SJonathan Haslam {
958b9e93c10SJonathan Haslam 	switch (cmd) {
959b9e93c10SJonathan Haslam 	case DDI_DETACH:
960b9e93c10SJonathan Haslam 		break;
961b9e93c10SJonathan Haslam 	case DDI_SUSPEND:
962b9e93c10SJonathan Haslam 		return (DDI_SUCCESS);
963b9e93c10SJonathan Haslam 	default:
964b9e93c10SJonathan Haslam 		return (DDI_FAILURE);
965b9e93c10SJonathan Haslam 	}
966b9e93c10SJonathan Haslam 
967b9e93c10SJonathan Haslam 	if (dtrace_unregister(dcpc_pid) != 0)
968b9e93c10SJonathan Haslam 		return (DDI_FAILURE);
969b9e93c10SJonathan Haslam 
970b9e93c10SJonathan Haslam 	ddi_remove_minor_node(devi, NULL);
971b9e93c10SJonathan Haslam 
972b9e93c10SJonathan Haslam 	mutex_enter(&cpu_lock);
973b9e93c10SJonathan Haslam 	unregister_cpu_setup_func(dcpc_cpu_setup, NULL);
974b9e93c10SJonathan Haslam 	mutex_exit(&cpu_lock);
975b9e93c10SJonathan Haslam 
976b9e93c10SJonathan Haslam 	kmem_free(dcpc_actv_reqs, cpc_ncounters * sizeof (dcpc_probe_t *));
977b9e93c10SJonathan Haslam 
978b9e93c10SJonathan Haslam 	kcpc_unregister_dcpc();
979b9e93c10SJonathan Haslam 
980b9e93c10SJonathan Haslam 	return (DDI_SUCCESS);
981b9e93c10SJonathan Haslam }
982b9e93c10SJonathan Haslam 
983b9e93c10SJonathan Haslam static int
984b9e93c10SJonathan Haslam dcpc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
985b9e93c10SJonathan Haslam {
986b9e93c10SJonathan Haslam 	uint_t caps;
987b9e93c10SJonathan Haslam 	char *attrs;
988b9e93c10SJonathan Haslam 
989b9e93c10SJonathan Haslam 	switch (cmd) {
990b9e93c10SJonathan Haslam 	case DDI_ATTACH:
991b9e93c10SJonathan Haslam 		break;
992b9e93c10SJonathan Haslam 	case DDI_RESUME:
993b9e93c10SJonathan Haslam 		return (DDI_SUCCESS);
994b9e93c10SJonathan Haslam 	default:
995b9e93c10SJonathan Haslam 		return (DDI_FAILURE);
996b9e93c10SJonathan Haslam 	}
997b9e93c10SJonathan Haslam 
998b9e93c10SJonathan Haslam 	if (kcpc_pcbe_loaded() == -1)
999b9e93c10SJonathan Haslam 		return (DDI_FAILURE);
1000b9e93c10SJonathan Haslam 
1001b9e93c10SJonathan Haslam 	caps = kcpc_pcbe_capabilities();
1002b9e93c10SJonathan Haslam 
1003b9e93c10SJonathan Haslam 	if (!(caps & CPC_CAP_OVERFLOW_INTERRUPT)) {
1004*8cb74972SJonathan Haslam 		cmn_err(CE_NOTE, "!dcpc: Counter Overflow not supported"\
1005*8cb74972SJonathan Haslam 		    " on this processor");
1006b9e93c10SJonathan Haslam 		return (DDI_FAILURE);
1007b9e93c10SJonathan Haslam 	}
1008b9e93c10SJonathan Haslam 
1009b9e93c10SJonathan Haslam 	if (ddi_create_minor_node(devi, "dcpc", S_IFCHR, 0,
1010b9e93c10SJonathan Haslam 	    DDI_PSEUDO, NULL) == DDI_FAILURE ||
1011b9e93c10SJonathan Haslam 	    dtrace_register("cpc", &dcpc_attr, DTRACE_PRIV_KERNEL,
1012b9e93c10SJonathan Haslam 	    NULL, &dcpc_pops, NULL, &dcpc_pid) != 0) {
1013b9e93c10SJonathan Haslam 		ddi_remove_minor_node(devi, NULL);
1014b9e93c10SJonathan Haslam 		return (DDI_FAILURE);
1015b9e93c10SJonathan Haslam 	}
1016b9e93c10SJonathan Haslam 
1017b9e93c10SJonathan Haslam 	mutex_enter(&cpu_lock);
1018b9e93c10SJonathan Haslam 	register_cpu_setup_func(dcpc_cpu_setup, NULL);
1019b9e93c10SJonathan Haslam 	mutex_exit(&cpu_lock);
1020b9e93c10SJonathan Haslam 
1021b9e93c10SJonathan Haslam 	dcpc_ovf_mask = (1 << cpc_ncounters) - 1;
1022b9e93c10SJonathan Haslam 	ASSERT(dcpc_ovf_mask != 0);
1023b9e93c10SJonathan Haslam 
1024b9e93c10SJonathan Haslam 	if (caps & CPC_CAP_OVERFLOW_PRECISE)
1025b9e93c10SJonathan Haslam 		dcpc_mult_ovf_cap = 1;
1026b9e93c10SJonathan Haslam 
1027b9e93c10SJonathan Haslam 	/*
1028b9e93c10SJonathan Haslam 	 * Determine which, if any, mask attribute the back-end can use.
1029b9e93c10SJonathan Haslam 	 */
1030b9e93c10SJonathan Haslam 	attrs = kcpc_list_attrs();
1031b9e93c10SJonathan Haslam 	if (strstr(attrs, "umask") != NULL)
1032b9e93c10SJonathan Haslam 		dcpc_mask_type |= DCPC_UMASK;
1033b9e93c10SJonathan Haslam 	else if (strstr(attrs, "emask") != NULL)
1034b9e93c10SJonathan Haslam 		dcpc_mask_type |= DCPC_EMASK;
1035b9e93c10SJonathan Haslam 
1036b9e93c10SJonathan Haslam 	/*
1037b9e93c10SJonathan Haslam 	 * The dcpc_actv_reqs array is used to store the requests that
1038b9e93c10SJonathan Haslam 	 * we currently have programmed. The order of requests in this
1039b9e93c10SJonathan Haslam 	 * array is not necessarily the order that the event appears in
1040b9e93c10SJonathan Haslam 	 * the kcpc_request_t array. Once entered into a slot in the array
1041b9e93c10SJonathan Haslam 	 * the entry is not moved until it's removed.
1042b9e93c10SJonathan Haslam 	 */
1043b9e93c10SJonathan Haslam 	dcpc_actv_reqs =
1044b9e93c10SJonathan Haslam 	    kmem_zalloc(cpc_ncounters * sizeof (dcpc_probe_t *), KM_SLEEP);
1045b9e93c10SJonathan Haslam 
1046b9e93c10SJonathan Haslam 	dcpc_min_overflow = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
1047b9e93c10SJonathan Haslam 	    DDI_PROP_DONTPASS, "dcpc-min-overflow", DCPC_MIN_OVF_DEFAULT);
1048b9e93c10SJonathan Haslam 
1049b9e93c10SJonathan Haslam 	kcpc_register_dcpc(dcpc_fire);
1050b9e93c10SJonathan Haslam 
1051b9e93c10SJonathan Haslam 	ddi_report_dev(devi);
1052b9e93c10SJonathan Haslam 	dcpc_devi = devi;
1053b9e93c10SJonathan Haslam 
1054b9e93c10SJonathan Haslam 	return (DDI_SUCCESS);
1055b9e93c10SJonathan Haslam }
1056b9e93c10SJonathan Haslam 
1057b9e93c10SJonathan Haslam static struct cb_ops dcpc_cb_ops = {
1058b9e93c10SJonathan Haslam 	dcpc_open,		/* open */
1059b9e93c10SJonathan Haslam 	nodev,			/* close */
1060b9e93c10SJonathan Haslam 	nulldev,		/* strategy */
1061b9e93c10SJonathan Haslam 	nulldev,		/* print */
1062b9e93c10SJonathan Haslam 	nodev,			/* dump */
1063b9e93c10SJonathan Haslam 	nodev,			/* read */
1064b9e93c10SJonathan Haslam 	nodev,			/* write */
1065b9e93c10SJonathan Haslam 	nodev,			/* ioctl */
1066b9e93c10SJonathan Haslam 	nodev,			/* devmap */
1067b9e93c10SJonathan Haslam 	nodev,			/* mmap */
1068b9e93c10SJonathan Haslam 	nodev,			/* segmap */
1069b9e93c10SJonathan Haslam 	nochpoll,		/* poll */
1070b9e93c10SJonathan Haslam 	ddi_prop_op,		/* cb_prop_op */
1071b9e93c10SJonathan Haslam 	0,			/* streamtab  */
1072b9e93c10SJonathan Haslam 	D_NEW | D_MP		/* Driver compatibility flag */
1073b9e93c10SJonathan Haslam };
1074b9e93c10SJonathan Haslam 
1075b9e93c10SJonathan Haslam static struct dev_ops dcpc_ops = {
1076b9e93c10SJonathan Haslam 	DEVO_REV,		/* devo_rev, */
1077b9e93c10SJonathan Haslam 	0,			/* refcnt  */
1078b9e93c10SJonathan Haslam 	dcpc_info,		/* get_dev_info */
1079b9e93c10SJonathan Haslam 	nulldev,		/* identify */
1080b9e93c10SJonathan Haslam 	nulldev,		/* probe */
1081b9e93c10SJonathan Haslam 	dcpc_attach,		/* attach */
1082b9e93c10SJonathan Haslam 	dcpc_detach,		/* detach */
1083b9e93c10SJonathan Haslam 	nodev,			/* reset */
1084b9e93c10SJonathan Haslam 	&dcpc_cb_ops,		/* driver operations */
1085b9e93c10SJonathan Haslam 	NULL,			/* bus operations */
1086b9e93c10SJonathan Haslam 	nodev,			/* dev power */
1087b9e93c10SJonathan Haslam 	ddi_quiesce_not_needed	/* quiesce */
1088b9e93c10SJonathan Haslam };
1089b9e93c10SJonathan Haslam 
1090b9e93c10SJonathan Haslam /*
1091b9e93c10SJonathan Haslam  * Module linkage information for the kernel.
1092b9e93c10SJonathan Haslam  */
1093b9e93c10SJonathan Haslam static struct modldrv modldrv = {
1094b9e93c10SJonathan Haslam 	&mod_driverops,		/* module type */
1095b9e93c10SJonathan Haslam 	"DTrace CPC Module",	/* name of module */
1096b9e93c10SJonathan Haslam 	&dcpc_ops,		/* driver ops */
1097b9e93c10SJonathan Haslam };
1098b9e93c10SJonathan Haslam 
1099b9e93c10SJonathan Haslam static struct modlinkage modlinkage = {
1100b9e93c10SJonathan Haslam 	MODREV_1,
1101b9e93c10SJonathan Haslam 	(void *)&modldrv,
1102b9e93c10SJonathan Haslam 	NULL
1103b9e93c10SJonathan Haslam };
1104b9e93c10SJonathan Haslam 
1105b9e93c10SJonathan Haslam int
1106b9e93c10SJonathan Haslam _init(void)
1107b9e93c10SJonathan Haslam {
1108b9e93c10SJonathan Haslam 	return (mod_install(&modlinkage));
1109b9e93c10SJonathan Haslam }
1110b9e93c10SJonathan Haslam 
1111b9e93c10SJonathan Haslam int
1112b9e93c10SJonathan Haslam _info(struct modinfo *modinfop)
1113b9e93c10SJonathan Haslam {
1114b9e93c10SJonathan Haslam 	return (mod_info(&modlinkage, modinfop));
1115b9e93c10SJonathan Haslam }
1116b9e93c10SJonathan Haslam 
1117b9e93c10SJonathan Haslam int
1118b9e93c10SJonathan Haslam _fini(void)
1119b9e93c10SJonathan Haslam {
1120b9e93c10SJonathan Haslam 	return (mod_remove(&modlinkage));
1121b9e93c10SJonathan Haslam }
1122