xref: /titanic_41/usr/src/uts/intel/pcbe/p123_pcbe.c (revision b02e9a2d4d2071d770e5aa9ae8f83f2bbe1f2ced)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Performance Counter Back-End for Pentiums I, II, and III.
30  */
31 
32 #include <sys/cpuvar.h>
33 #include <sys/param.h>
34 #include <sys/cpc_impl.h>
35 #include <sys/cpc_pcbe.h>
36 #include <sys/modctl.h>
37 #include <sys/inttypes.h>
38 #include <sys/systm.h>
39 #include <sys/cmn_err.h>
40 #include <sys/x86_archext.h>
41 #include <sys/sdt.h>
42 #include <sys/archsystm.h>
43 #include <sys/privregs.h>
44 #include <sys/ddi.h>
45 #include <sys/sunddi.h>
46 
47 static int64_t diff3931(uint64_t sample, uint64_t old);
48 static uint64_t trunc3931(uint64_t value);
49 
50 static int ptm_pcbe_init(void);
51 static uint_t ptm_pcbe_ncounters(void);
52 static const char *ptm_pcbe_impl_name(void);
53 static const char *ptm_pcbe_cpuref(void);
54 static char *ptm_pcbe_list_events(uint_t picnum);
55 static char *ptm_pcbe_list_attrs(void);
56 static uint64_t ptm_pcbe_event_coverage(char *event);
57 static int ptm_pcbe_pic_index(char *picname);
58 static uint64_t	ptm_pcbe_overflow_bitmap(void);
59 static int ptm_pcbe_configure(uint_t picnum, char *event, uint64_t preset,
60     uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data,
61     void *token);
62 static void ptm_pcbe_program(void *token);
63 static void ptm_pcbe_allstop(void);
64 static void ptm_pcbe_sample(void *token);
65 static void ptm_pcbe_free(void *config);
66 
67 pcbe_ops_t ptm_pcbe_ops = {
68 	PCBE_VER_1,
69 	0,
70 	ptm_pcbe_ncounters,
71 	ptm_pcbe_impl_name,
72 	ptm_pcbe_cpuref,
73 	ptm_pcbe_list_events,
74 	ptm_pcbe_list_attrs,
75 	ptm_pcbe_event_coverage,
76 	ptm_pcbe_overflow_bitmap,
77 	ptm_pcbe_configure,
78 	ptm_pcbe_program,
79 	ptm_pcbe_allstop,
80 	ptm_pcbe_sample,
81 	ptm_pcbe_free
82 };
83 
84 typedef enum _ptm_ver {
85 	PTM_VER_P5,
86 	PTM_VER_P6
87 } ptm_ver_t;
88 
89 static ptm_ver_t ptm_ver;
90 static const char *ptm_impl_name;
91 static const char *ptm_cpuref;
92 static char *pic_events[2] = { NULL, NULL };
93 
94 /*
95  * Indicates whether the "rdpmc" instruction is available on this processor.
96  */
97 static int ptm_rdpmc_avail = 0;
98 
99 #define	ALL_STOPPED	0ULL
100 
101 typedef struct _ptm_pcbe_config {
102 	uint8_t		ptm_picno;	/* 0 for pic0 or 1 for pic1 */
103 	uint32_t	ptm_ctl;    /* P6: PerfEventSelect; P5: cesr, shifted */
104 	uint64_t	ptm_rawpic;
105 } ptm_pcbe_config_t;
106 
107 struct nametable {
108 	uint8_t		bits;
109 	const char	*name;
110 };
111 
112 #define	NT_END 0xFF
113 
114 /*
115  * Basic Pentium events
116  */
117 #define	P5_EVENTS				\
118 	{0x0,	"data_read"},			\
119 	{0x1,	"data_write"},			\
120 	{0x2,	"data_tlb_miss"},		\
121 	{0x3,	"data_read_miss"},		\
122 	{0x4,	"data_write_miss"},		\
123 	{0x5,	"write_hit_to_M_or_E"},		\
124 	{0x6,	"dcache_lines_wrback"},		\
125 	{0x7,	"external_snoops"},		\
126 	{0x8,	"external_dcache_snoop_hits"},	\
127 	{0x9,	"memory_access_in_both_pipes"},	\
128 	{0xa,	"bank_conflicts"},		\
129 	{0xb,	"misaligned_ref"},		\
130 	{0xc,	"code_read"},			\
131 	{0xd,	"code_tlb_miss"},		\
132 	{0xe,	"code_cache_miss"},		\
133 	{0xf,	"any_segreg_loaded"},		\
134 	{0x12,	"branches"},			\
135 	{0x13,	"btb_hits"},			\
136 	{0x14,	"taken_or_btb_hit"},		\
137 	{0x15,	"pipeline_flushes"},		\
138 	{0x16,	"instr_exec"},			\
139 	{0x17,	"instr_exec_V_pipe"},		\
140 	{0x18,	"clks_bus_cycle"},		\
141 	{0x19,	"clks_full_wbufs"},		\
142 	{0x1a,	"pipe_stall_read"},		\
143 	{0x1b,	"stall_on_write_ME"},		\
144 	{0x1c,	"locked_bus_cycle"},		\
145 	{0x1d,	"io_rw_cycles"},		\
146 	{0x1e,	"reads_noncache_mem"},		\
147 	{0x1f,	"pipeline_agi_stalls"},		\
148 	{0x22,	"flops"},			\
149 	{0x23,	"bp_match_dr0"},		\
150 	{0x24,	"bp_match_dr1"},		\
151 	{0x25,	"bp_match_dr2"},		\
152 	{0x26,	"bp_match_dr3"},		\
153 	{0x27,	"hw_intrs"},			\
154 	{0x28,	"data_rw"},			\
155 	{0x29,	"data_rw_miss"}
156 
157 static const struct nametable P5mmx_names0[] = {
158 	P5_EVENTS,
159 	{0x2a,	"bus_ownership_latency"},
160 	{0x2b,	"mmx_instr_upipe"},
161 	{0x2c,	"cache_M_line_sharing"},
162 	{0x2d,	"emms_instr"},
163 	{0x2e,	"bus_util_processor"},
164 	{0x2f,	"sat_mmx_instr"},
165 	{0x30,	"clks_not_HLT"},
166 	{0x31,	"mmx_data_read"},
167 	{0x32,	"clks_fp_stall"},
168 	{0x33,	"d1_starv_fifo_0"},
169 	{0x34,	"mmx_data_write"},
170 	{0x35,	"pipe_flush_wbp"},
171 	{0x36,	"mmx_misalign_data_refs"},
172 	{0x37,	"rets_pred_incorrect"},
173 	{0x38,	"mmx_multiply_unit_interlock"},
174 	{0x39,	"rets"},
175 	{0x3a,	"btb_false_entries"},
176 	{0x3b,	"clocks_stall_full_wb"},
177 	{NT_END, ""}
178 };
179 
180 static const struct nametable P5mmx_names1[] = {
181 	P5_EVENTS,
182 	{0x2a,	"bus_ownership_transfers"},
183 	{0x2b,	"mmx_instr_vpipe"},
184 	{0x2c,	"cache_lint_sharing"},
185 	{0x2d,	"mmx_fp_transitions"},
186 	{0x2e,	"writes_noncache_mem"},
187 	{0x2f,	"sats_performed"},
188 	{0x30,	"clks_dcache_tlb_miss"},
189 	{0x31,	"mmx_data_read_miss"},
190 	{0x32,	"taken_br"},
191 	{0x33,	"d1_starv_fifo_1"},
192 	{0x34,	"mmx_data_write_miss"},
193 	{0x35,	"pipe_flush_wbp_wb"},
194 	{0x36,	"mmx_pipe_stall_data_read"},
195 	{0x37,	"rets_pred"},
196 	{0x38,	"movd_movq_stall"},
197 	{0x39,	"rsb_overflow"},
198 	{0x3a,	"btb_mispred_nt"},
199 	{0x3b,	"mmx_stall_write_ME"},
200 	{NT_END, ""}
201 };
202 
203 static const struct nametable *P5mmx_names[2] = {
204 	P5mmx_names0,
205 	P5mmx_names1
206 };
207 
208 /*
209  * Pentium Pro and Pentium II events
210  */
211 static const struct nametable _P6_names[] = {
212 	/*
213 	 * Data cache unit
214 	 */
215 	{0x43,	"data_mem_refs"},
216 	{0x45,	"dcu_lines_in"},
217 	{0x46,	"dcu_m_lines_in"},
218 	{0x47,	"dcu_m_lines_out"},
219 	{0x48,	"dcu_miss_outstanding"},
220 
221 	/*
222 	 * Instruction fetch unit
223 	 */
224 	{0x80,	"ifu_ifetch"},
225 	{0x81,	"ifu_ifetch_miss"},
226 	{0x85,	"itlb_miss"},
227 	{0x86,	"ifu_mem_stall"},
228 	{0x87,	"ild_stall"},
229 
230 	/*
231 	 * L2 cache
232 	 */
233 	{0x28,	"l2_ifetch"},
234 	{0x29,	"l2_ld"},
235 	{0x2a,	"l2_st"},
236 	{0x24,	"l2_lines_in"},
237 	{0x26,	"l2_lines_out"},
238 	{0x25,	"l2_m_lines_inm"},
239 	{0x27,	"l2_m_lines_outm"},
240 	{0x2e,	"l2_rqsts"},
241 	{0x21,	"l2_ads"},
242 	{0x22,	"l2_dbus_busy"},
243 	{0x23,	"l2_dbus_busy_rd"},
244 
245 	/*
246 	 * External bus logic
247 	 */
248 	{0x62,	"bus_drdy_clocks"},
249 	{0x63,	"bus_lock_clocks"},
250 	{0x60,	"bus_req_outstanding"},
251 	{0x65,	"bus_tran_brd"},
252 	{0x66,	"bus_tran_rfo"},
253 	{0x67,	"bus_trans_wb"},
254 	{0x68,	"bus_tran_ifetch"},
255 	{0x69,	"bus_tran_inval"},
256 	{0x6a,	"bus_tran_pwr"},
257 	{0x6b,	"bus_trans_p"},
258 	{0x6c,	"bus_trans_io"},
259 	{0x6d,	"bus_tran_def"},
260 	{0x6e,	"bus_tran_burst"},
261 	{0x70,	"bus_tran_any"},
262 	{0x6f,	"bus_tran_mem"},
263 	{0x64,	"bus_data_rcv"},
264 	{0x61,	"bus_bnr_drv"},
265 	{0x7a,	"bus_hit_drv"},
266 	{0x7b,	"bus_hitm_drv"},
267 	{0x7e,	"bus_snoop_stall"},
268 
269 	/*
270 	 * Floating point unit
271 	 */
272 	{0xc1,	"flops"},		/* 0 only */
273 	{0x10,	"fp_comp_ops_exe"},	/* 0 only */
274 	{0x11,	"fp_assist"},		/* 1 only */
275 	{0x12,	"mul"},			/* 1 only */
276 	{0x13,	"div"},			/* 1 only */
277 	{0x14,	"cycles_div_busy"},	/* 0 only */
278 
279 	/*
280 	 * Memory ordering
281 	 */
282 	{0x3,	"ld_blocks"},
283 	{0x4,	"sb_drains"},
284 	{0x5,	"misalign_mem_ref"},
285 
286 	/*
287 	 * Instruction decoding and retirement
288 	 */
289 	{0xc0,	"inst_retired"},
290 	{0xc2,	"uops_retired"},
291 	{0xd0,	"inst_decoder"},
292 
293 	/*
294 	 * Interrupts
295 	 */
296 	{0xc8,	"hw_int_rx"},
297 	{0xc6,	"cycles_int_masked"},
298 	{0xc7,	"cycles_int_pending_and_masked"},
299 
300 	/*
301 	 * Branches
302 	 */
303 	{0xc4,	"br_inst_retired"},
304 	{0xc5,	"br_miss_pred_retired"},
305 	{0xc9,	"br_taken_retired"},
306 	{0xca,	"br_miss_pred_taken_ret"},
307 	{0xe0,	"br_inst_decoded"},
308 	{0xe2,	"btb_misses"},
309 	{0xe4,	"br_bogus"},
310 	{0xe6,	"baclears"},
311 
312 	/*
313 	 * Stalls
314 	 */
315 	{0xa2,	"resource_stalls"},
316 	{0xd2,	"partial_rat_stalls"},
317 
318 	/*
319 	 * Segment register loads
320 	 */
321 	{0x6,	"segment_reg_loads"},
322 
323 	/*
324 	 * Clocks
325 	 */
326 	{0x79,	"cpu_clk_unhalted"},
327 
328 	/*
329 	 * MMX
330 	 */
331 	{0xb0,	"mmx_instr_exec"},
332 	{0xb1,	"mmx_sat_instr_exec"},
333 	{0xb2,	"mmx_uops_exec"},
334 	{0xb3,	"mmx_instr_type_exec"},
335 	{0xcc,	"fp_mmx_trans"},
336 	{0xcd,	"mmx_assists"},
337 	{0xce,	"mmx_instr_ret"},
338 	{0xd4,	"seg_rename_stalls"},
339 	{0xd5,	"seg_reg_renames"},
340 	{0xd6,	"ret_seg_renames"},
341 
342 	{NT_END, ""}
343 };
344 
345 static const struct nametable *P6_names[2] = {
346 	_P6_names,
347 	_P6_names
348 };
349 
350 static const struct nametable **events;
351 
352 #define	BITS(v, u, l)	\
353 	(((v) >> (l)) & ((1 << (1 + (u) - (l))) - 1))
354 
355 /*
356  * "Well known" bit fields in the Pentium CES register
357  * The interfaces in libcpc should make these #defines uninteresting.
358  */
359 #define	CPC_P5_CESR_ES0_SHIFT	0
360 #define	CPC_P5_CESR_ES0_MASK	0x3f
361 #define	CPC_P5_CESR_ES1_SHIFT	16
362 #define	CPC_P5_CESR_ES1_MASK	0x3f
363 
364 #define	CPC_P5_CESR_OS0		6
365 #define	CPC_P5_CESR_USR0	7
366 #define	CPC_P5_CESR_CLK0	8
367 #define	CPC_P5_CESR_PC0		9
368 #define	CPC_P5_CESR_OS1		(CPC_P5_CESR_OS0 + 16)
369 #define	CPC_P5_CESR_USR1	(CPC_P5_CESR_USR0 + 16)
370 #define	CPC_P5_CESR_CLK1	(CPC_P5_CESR_CLK0 + 16)
371 #define	CPC_P5_CESR_PC1		(CPC_P5_CESR_PC0 + 16)
372 
373 /*
374  * "Well known" bit fields in the Pentium Pro PerfEvtSel registers
375  * The interfaces in libcpc should make these #defines uninteresting.
376  */
377 #define	CPC_P6_PES_INV		23
378 #define	CPC_P6_PES_EN		22
379 #define	CPC_P6_PES_INT		20
380 #define	CPC_P6_PES_PC		19
381 #define	CPC_P6_PES_E		18
382 #define	CPC_P6_PES_OS		17
383 #define	CPC_P6_PES_USR		16
384 
385 #define	CPC_P6_PES_UMASK_SHIFT	8
386 #define	CPC_P6_PES_UMASK_MASK	(0xffu)
387 
388 #define	CPC_P6_PES_CMASK_SHIFT	24
389 #define	CPC_P6_PES_CMASK_MASK	(0xffu)
390 
391 #define	CPC_P6_PES_PIC0_MASK	(0xffu)
392 #define	CPC_P6_PES_PIC1_MASK	(0xffu)
393 
394 #define	P6_PES_EN	(UINT32_C(1) << CPC_P6_PES_EN)
395 #define	P6_PES_INT	(UINT32_C(1) << CPC_P6_PES_INT)
396 #define	P6_PES_OS	(UINT32_C(1) << CPC_P6_PES_OS)
397 
398 /*
399  * Pentium 5 attributes
400  */
401 #define	P5_NOEDGE	0x1	/* "noedge"	- no edge detection */
402 #define	P5_PC		0x2	/* "pc"		- pin control */
403 
404 /*
405  * Pentium 6 attributes
406  */
407 #define	P6_NOEDGE	0x1
408 #define	P6_PC		0x2
409 #define	P6_INV		0x4	/* "inv" - count inverted transitions */
410 #define	P6_INT		0x8	/* "int" - interrupt on overflow */
411 
412 /*
413  * CPU reference strings
414  */
415 
416 #define	P5_CPUREF	"See Appendix A.4 of the \"IA-32 Intel Architecture "  \
417 			"Software Developer's Manual Volume 3: System "	       \
418 			"Programming Guide,\" Order # 245472-012, 2003"
419 
420 #define	P6_CPUREF	"See Appendix A.3 of the \"IA-32 Intel Architecture "  \
421 			"Software Developer's Manual Volume 3: System "	       \
422 			"Programming Guide,\" Order # 245472-012, 2003"
423 
424 static int
425 ptm_pcbe_init(void)
426 {
427 	const struct nametable	*n;
428 	int			i;
429 	size_t			size;
430 
431 	if (x86_feature & X86_MMX)
432 		ptm_rdpmc_avail = 1;
433 
434 	/*
435 	 * Discover type of CPU and set events pointer appropriately.
436 	 *
437 	 * Map family and model into the performance
438 	 * counter architectures we currently understand.
439 	 *
440 	 * See application note AP485 (from developer.intel.com)
441 	 * for further explanation.
442 	 */
443 	if (cpuid_getvendor(CPU) != X86_VENDOR_Intel)
444 		return (-1);
445 	switch (cpuid_getfamily(CPU)) {
446 	case 5:		/* Pentium and Pentium with MMX */
447 		events = P5mmx_names;
448 		ptm_ver = PTM_VER_P5;
449 		ptm_cpuref = P5_CPUREF;
450 		if (cpuid_getmodel(CPU) < 4)
451 			ptm_impl_name = "Pentium";
452 		else
453 			ptm_impl_name = "Pentium with MMX";
454 		break;
455 	case 6:		/* Pentium Pro and Pentium II and III */
456 		events = P6_names;
457 		ptm_ver = PTM_VER_P6;
458 		ptm_cpuref = P6_CPUREF;
459 		ptm_pcbe_ops.pcbe_caps = CPC_CAP_OVERFLOW_INTERRUPT;
460 		if (x86_feature & X86_MMX)
461 			ptm_impl_name = "Pentium Pro with MMX, Pentium II";
462 		else
463 			ptm_impl_name = "Pentium Pro, Pentium II";
464 		break;
465 	default:
466 		return (-1);
467 	}
468 
469 	/*
470 	 * Initialize the list of events for each PIC.
471 	 * Do two passes: one to compute the size necessary and another
472 	 * to copy the strings. Need room for event, comma, and NULL terminator.
473 	 */
474 	for (i = 0; i < 2; i++) {
475 		size = 0;
476 		for (n = events[i]; n->bits != NT_END; n++)
477 			size += strlen(n->name) + 1;
478 		pic_events[i] = kmem_alloc(size + 1, KM_SLEEP);
479 		*pic_events[i] = '\0';
480 		for (n = events[i]; n->bits != NT_END; n++) {
481 			(void) strcat(pic_events[i], n->name);
482 			(void) strcat(pic_events[i], ",");
483 		}
484 		/*
485 		 * Remove trailing comma.
486 		 */
487 		pic_events[i][size - 1] = '\0';
488 	}
489 
490 	return (0);
491 }
492 
493 static uint_t
494 ptm_pcbe_ncounters(void)
495 {
496 	return (2);
497 }
498 
499 static const char *
500 ptm_pcbe_impl_name(void)
501 {
502 	return (ptm_impl_name);
503 }
504 
505 static const char *
506 ptm_pcbe_cpuref(void)
507 {
508 	return (ptm_cpuref);
509 }
510 
511 static char *
512 ptm_pcbe_list_events(uint_t picnum)
513 {
514 	ASSERT(picnum >= 0 && picnum < cpc_ncounters);
515 
516 	if (pic_events[0] == NULL) {
517 		ASSERT(pic_events[1] == NULL);
518 	}
519 
520 	return (pic_events[picnum]);
521 }
522 
523 static char *
524 ptm_pcbe_list_attrs(void)
525 {
526 	if (ptm_ver == PTM_VER_P5)
527 		return ("noedge,pc");
528 	else
529 		return ("noedge,pc,inv,int,umask,cmask");
530 }
531 
532 static const struct nametable *
533 find_event(int regno, char *name)
534 {
535 	const struct nametable *n;
536 
537 	n = events[regno];
538 
539 	for (; n->bits != NT_END; n++)
540 		if (strcmp(name, n->name) == 0)
541 			return (n);
542 
543 	return (NULL);
544 }
545 
546 static uint64_t
547 ptm_pcbe_event_coverage(char *event)
548 {
549 	uint64_t bitmap = 0;
550 
551 	if (find_event(0, event) != NULL)
552 		bitmap = 0x1;
553 	if (find_event(1, event) != NULL)
554 		bitmap |= 0x2;
555 
556 	return (bitmap);
557 }
558 
559 static uint64_t
560 ptm_pcbe_overflow_bitmap(void)
561 {
562 	uint64_t	ret = 0;
563 	uint64_t	pes[2];
564 
565 	/*
566 	 * P5 is not capable of generating interrupts.
567 	 */
568 	ASSERT(ptm_ver == PTM_VER_P6);
569 
570 	/*
571 	 * CPC could have caused an interrupt provided that
572 	 *
573 	 * 1) Counters are enabled
574 	 * 2) Either counter has requested an interrupt
575 	 */
576 
577 	pes[0] = rdmsr(REG_PERFEVNT0);
578 	if (((uint32_t)pes[0] & P6_PES_EN) != P6_PES_EN)
579 		return (0);
580 
581 	/*
582 	 * If a particular counter requested an interrupt, assume it caused
583 	 * this interrupt. There is no way to determine which counter overflowed
584 	 * on this hardware other than by using unreliable heuristics.
585 	 */
586 
587 	pes[1] = rdmsr(REG_PERFEVNT1);
588 	if ((uint32_t)pes[0] & P6_PES_INT)
589 		ret |= 0x1;
590 	if ((uint32_t)pes[1] & P6_PES_INT)
591 		ret |= 0x2;
592 
593 	return (ret);
594 }
595 
596 /*ARGSUSED*/
597 static int
598 ptm_pcbe_configure(uint_t picnum, char *eventname, uint64_t preset,
599     uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data,
600     void *token)
601 {
602 	ptm_pcbe_config_t	*conf;
603 	const struct nametable	*n;
604 	struct nametable	nt_raw = { 0, "raw" };
605 	int			i;
606 	int			ptm_flags = 0;
607 
608 	/*
609 	 * If we've been handed an existing configuration, we need only preset
610 	 * the counter value.
611 	 */
612 	if (*data != NULL) {
613 		conf = *data;
614 		conf->ptm_rawpic = trunc3931(preset);
615 		return (0);
616 	}
617 
618 	if (picnum != 0 && picnum != 1)
619 		return (CPC_INVALID_PICNUM);
620 
621 	if ((n = find_event(picnum, eventname)) == NULL) {
622 		long tmp;
623 
624 		/*
625 		 * If ddi_strtol() likes this event, use it as a raw event code.
626 		 */
627 		if (ddi_strtol(eventname, NULL, 0, &tmp) != 0)
628 			return (CPC_INVALID_EVENT);
629 
630 		nt_raw.bits = tmp;
631 
632 		if (ptm_ver == PTM_VER_P5)
633 			nt_raw.bits &= CPC_P5_CESR_ES0_MASK;
634 		else
635 			nt_raw.bits &= CPC_P6_PES_PIC0_MASK;
636 
637 		n = &nt_raw;
638 	}
639 
640 	conf = kmem_alloc(sizeof (ptm_pcbe_config_t), KM_SLEEP);
641 
642 	conf->ptm_picno = picnum;
643 	conf->ptm_rawpic = trunc3931(preset);
644 	conf->ptm_ctl = 0;
645 
646 	if (ptm_ver == PTM_VER_P5) {
647 		int picshift;
648 		picshift = (picnum == 0) ? 0 : 16;
649 
650 		for (i = 0; i < nattrs; i++) {
651 			/*
652 			 * Value of these attributes is ignored; their presence
653 			 * alone tells us to set the corresponding flag.
654 			 */
655 			if (strncmp(attrs[i].ka_name, "noedge", 7) == 0) {
656 				if (attrs[i].ka_val != 0)
657 					ptm_flags |= P5_NOEDGE;
658 			} else if (strncmp(attrs[i].ka_name, "pc", 3) == 0) {
659 				if (attrs[i].ka_val != 0)
660 					ptm_flags |= P5_PC;
661 			} else {
662 				kmem_free(conf, sizeof (ptm_pcbe_config_t));
663 				return (CPC_INVALID_ATTRIBUTE);
664 			}
665 		}
666 
667 		if (flags & CPC_COUNT_USER)
668 			conf->ptm_ctl |= (1 << (CPC_P5_CESR_USR0 + picshift));
669 		if (flags & CPC_COUNT_SYSTEM)
670 			conf->ptm_ctl |= (1 << (CPC_P5_CESR_OS0 + picshift));
671 		if (ptm_flags & P5_NOEDGE)
672 			conf->ptm_ctl |= (1 << (CPC_P5_CESR_CLK0 + picshift));
673 		if (ptm_flags & P5_PC)
674 			conf->ptm_ctl |= (1 << (CPC_P5_CESR_PC0 + picshift));
675 
676 		ASSERT((n->bits | CPC_P5_CESR_ES0_MASK) ==
677 		    CPC_P5_CESR_ES0_MASK);
678 
679 		conf->ptm_ctl |= (n->bits << picshift);
680 	} else {
681 		for (i = 0; i < nattrs; i++) {
682 			if (strncmp(attrs[i].ka_name, "noedge", 6) == 0) {
683 				if (attrs[i].ka_val != 0)
684 					ptm_flags |= P6_NOEDGE;
685 			} else if (strncmp(attrs[i].ka_name, "pc", 2) == 0) {
686 				if (attrs[i].ka_val != 0)
687 					ptm_flags |= P6_PC;
688 			} else if (strncmp(attrs[i].ka_name, "inv", 3) == 0) {
689 				if (attrs[i].ka_val != 0)
690 					ptm_flags |= P6_INV;
691 			} else if (strncmp(attrs[i].ka_name, "umask", 5) == 0) {
692 				if ((attrs[i].ka_val | CPC_P6_PES_UMASK_MASK) !=
693 				    CPC_P6_PES_UMASK_MASK) {
694 					kmem_free(conf,
695 					    sizeof (ptm_pcbe_config_t));
696 					return (CPC_ATTRIBUTE_OUT_OF_RANGE);
697 				}
698 				conf->ptm_ctl |= (uint8_t)attrs[i].ka_val <<
699 				    CPC_P6_PES_UMASK_SHIFT;
700 			} else if (strncmp(attrs[i].ka_name, "cmask", 5) == 0) {
701 				if ((attrs[i].ka_val | CPC_P6_PES_CMASK_MASK) !=
702 				    CPC_P6_PES_CMASK_MASK) {
703 					kmem_free(conf,
704 					    sizeof (ptm_pcbe_config_t));
705 					return (CPC_ATTRIBUTE_OUT_OF_RANGE);
706 				}
707 				conf->ptm_ctl |= (uint8_t)attrs[i].ka_val <<
708 				    CPC_P6_PES_CMASK_SHIFT;
709 			} else if (strncmp(attrs[i].ka_name, "int", 3) == 0) {
710 				if (attrs[i].ka_val != 0)
711 					ptm_flags |= P6_INT;
712 			} else {
713 				kmem_free(conf, sizeof (ptm_pcbe_config_t));
714 				return (CPC_INVALID_ATTRIBUTE);
715 			}
716 		}
717 
718 		if (flags & CPC_OVF_NOTIFY_EMT)
719 			/*
720 			 * If the user has requested notification of overflows,
721 			 * we automatically program the hardware to generate
722 			 * overflow interrupts.
723 			 */
724 			ptm_flags |= P6_INT;
725 		if (flags & CPC_COUNT_USER)
726 			conf->ptm_ctl |= (1 << CPC_P6_PES_USR);
727 		if (flags & CPC_COUNT_SYSTEM)
728 			conf->ptm_ctl |= (1 << CPC_P6_PES_OS);
729 		if ((ptm_flags & P6_NOEDGE) == 0)
730 			conf->ptm_ctl |= (1 << CPC_P6_PES_E);
731 		if (ptm_flags & P6_PC)
732 			conf->ptm_ctl |= (1 << CPC_P6_PES_PC);
733 		if (ptm_flags & P6_INV)
734 			conf->ptm_ctl |= (1 << CPC_P6_PES_INV);
735 		if (ptm_flags & P6_INT)
736 			conf->ptm_ctl |= (1 << CPC_P6_PES_INT);
737 
738 		ASSERT((n->bits | CPC_P6_PES_PIC0_MASK) ==
739 		    CPC_P6_PES_PIC0_MASK);
740 
741 		conf->ptm_ctl |= n->bits;
742 	}
743 
744 	*data = conf;
745 	return (0);
746 }
747 
748 static void
749 ptm_pcbe_program(void *token)
750 {
751 	ptm_pcbe_config_t	*pic0;
752 	ptm_pcbe_config_t	*pic1;
753 	ptm_pcbe_config_t	*tmp;
754 	ptm_pcbe_config_t	empty = { 1, 0, 0 }; /* assume pic1 to start */
755 
756 	if ((pic0 = kcpc_next_config(token, NULL, NULL)) == NULL)
757 		panic("ptm_pcbe: token %p has no configs", token);
758 
759 	if ((pic1 = kcpc_next_config(token, pic0, NULL)) == NULL)
760 		pic1 = &empty;
761 
762 	if (pic0->ptm_picno != 0) {
763 		empty.ptm_picno = 0;
764 		tmp = pic1;
765 		pic1 = pic0;
766 		pic0 = tmp;
767 	}
768 
769 	ASSERT(pic0->ptm_picno == 0 && pic1->ptm_picno == 1);
770 
771 	if (ptm_rdpmc_avail) {
772 		ulong_t curcr4 = getcr4();
773 		if (kcpc_allow_nonpriv(token))
774 			setcr4(curcr4 | CR4_PCE);
775 		else
776 			setcr4(curcr4 & ~CR4_PCE);
777 	}
778 
779 	if (ptm_ver == PTM_VER_P5) {
780 		wrmsr(P5_CESR, ALL_STOPPED);
781 		wrmsr(P5_CTR0, pic0->ptm_rawpic);
782 		wrmsr(P5_CTR1, pic1->ptm_rawpic);
783 		wrmsr(P5_CESR, pic0->ptm_ctl | pic1->ptm_ctl);
784 		pic0->ptm_rawpic = rdmsr(P5_CTR0);
785 		pic1->ptm_rawpic = rdmsr(P5_CTR1);
786 	} else {
787 		uint64_t	pes;
788 		wrmsr(REG_PERFEVNT0, ALL_STOPPED);
789 		wrmsr(REG_PERFCTR0, pic0->ptm_rawpic);
790 		wrmsr(REG_PERFCTR1, pic1->ptm_rawpic);
791 		pes = pic1->ptm_ctl;
792 		DTRACE_PROBE1(ptm__pes1, uint64_t, pes);
793 		wrmsr(REG_PERFEVNT1, pes);
794 		pes = pic0->ptm_ctl | (1 << CPC_P6_PES_EN);
795 		DTRACE_PROBE1(ptm__pes0, uint64_t, pes);
796 		wrmsr(REG_PERFEVNT0, pes);
797 	}
798 }
799 
800 static void
801 ptm_pcbe_allstop(void)
802 {
803 	if (ptm_ver == PTM_VER_P5)
804 		wrmsr(P5_CESR, ALL_STOPPED);
805 	else {
806 		wrmsr(REG_PERFEVNT0, ALL_STOPPED);
807 		setcr4(getcr4() & ~CR4_PCE);
808 	}
809 }
810 
811 static void
812 ptm_pcbe_sample(void *token)
813 {
814 	ptm_pcbe_config_t	*pic0;
815 	ptm_pcbe_config_t	*pic1;
816 	ptm_pcbe_config_t	*swap;
817 	ptm_pcbe_config_t	empty = { 1, 0, 0 }; /* assume pic1 to start */
818 	uint64_t		tmp;
819 	uint64_t		*pic0_data;
820 	uint64_t		*pic1_data;
821 	uint64_t		*dtmp;
822 	uint64_t		curpic[2];
823 
824 	if ((pic0 = kcpc_next_config(token, NULL, &pic0_data)) == NULL)
825 		panic("ptm_pcbe: token %p has no configs", token);
826 
827 	if ((pic1 = kcpc_next_config(token, pic0, &pic1_data)) == NULL) {
828 		pic1 = &empty;
829 		pic1_data = &tmp;
830 	}
831 
832 	if (pic0->ptm_picno != 0) {
833 		empty.ptm_picno = 0;
834 		swap = pic0;
835 		pic0 = pic1;
836 		pic1 = swap;
837 		dtmp = pic0_data;
838 		pic0_data = pic1_data;
839 		pic1_data = dtmp;
840 	}
841 
842 	ASSERT(pic0->ptm_picno == 0 && pic1->ptm_picno == 1);
843 
844 	if (ptm_ver == PTM_VER_P5) {
845 		curpic[0] = rdmsr(P5_CTR0);
846 		curpic[1] = rdmsr(P5_CTR1);
847 	} else {
848 		curpic[0] = rdmsr(REG_PERFCTR0);
849 		curpic[1] = rdmsr(REG_PERFCTR1);
850 	}
851 
852 	DTRACE_PROBE1(ptm__curpic0, uint64_t, curpic[0]);
853 	DTRACE_PROBE1(ptm__curpic1, uint64_t, curpic[1]);
854 
855 	*pic0_data += diff3931(curpic[0], pic0->ptm_rawpic);
856 	pic0->ptm_rawpic = trunc3931(*pic0_data);
857 
858 	*pic1_data += diff3931(curpic[1], pic1->ptm_rawpic);
859 	pic1->ptm_rawpic = trunc3931(*pic1_data);
860 }
861 
862 static void
863 ptm_pcbe_free(void *config)
864 {
865 	kmem_free(config, sizeof (ptm_pcbe_config_t));
866 }
867 
868 /*
869  * Virtualizes the 40-bit field of the %pic
870  * register into a 64-bit software register.
871  *
872  * We can retrieve 40 (signed) bits from the counters,
873  * but we can set only 32 (signed) bits into the counters.
874  * This makes virtualizing more than 31-bits of registers
875  * quite tricky.
876  *
877  * If bits 39 to 31 are set in the virtualized pic register,
878  * then we can preset the counter to this value using the fact
879  * that wrmsr sign extends bit 31.   Though it might look easier
880  * to only use the bottom 31-bits of the register, we have to allow
881  * the full 40-bits to be used to perform overflow profiling.
882  */
883 
884 #define	MASK40		UINT64_C(0xffffffffff)
885 #define	MASK31		UINT64_C(0x7fffffff)
886 #define	BITS_39_31	UINT64_C(0xff80000000)
887 
888 static int64_t
889 diff3931(uint64_t sample, uint64_t old)
890 {
891 	int64_t diff;
892 
893 	if ((old & BITS_39_31) == BITS_39_31) {
894 		diff = (MASK40 & sample) - old;
895 		if (diff < 0)
896 			diff += (UINT64_C(1) << 40);
897 	} else {
898 		diff = (MASK31 & sample) - old;
899 		if (diff < 0)
900 			diff += (UINT64_C(1) << 31);
901 	}
902 	return (diff);
903 }
904 
905 static uint64_t
906 trunc3931(uint64_t value)
907 {
908 	if ((value & BITS_39_31) == BITS_39_31)
909 		return (MASK40 & value);
910 	return (MASK31 & value);
911 }
912 
913 static struct modlpcbe modlpcbe = {
914 	&mod_pcbeops,
915 	"Pentium Performance Counters v%I%",
916 	&ptm_pcbe_ops
917 };
918 
919 static struct modlinkage modl = {
920 	MODREV_1,
921 	&modlpcbe,
922 };
923 
924 int
925 _init(void)
926 {
927 	if (ptm_pcbe_init() != 0)
928 		return (ENOTSUP);
929 	return (mod_install(&modl));
930 }
931 
932 int
933 _fini(void)
934 {
935 	return (mod_remove(&modl));
936 }
937 
938 int
939 _info(struct modinfo *mi)
940 {
941 	return (mod_info(&modl, mi));
942 }
943