xref: /onnv-gate/usr/src/uts/sun4v/cpu/niagara_perfctr.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/async.h>
31*0Sstevel@tonic-gate #include <sys/sunddi.h>
32*0Sstevel@tonic-gate #include <sys/sunndi.h>
33*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
34*0Sstevel@tonic-gate #include <sys/machsystm.h>
35*0Sstevel@tonic-gate #include <sys/niagararegs.h>
36*0Sstevel@tonic-gate #include <sys/hypervisor_api.h>
37*0Sstevel@tonic-gate #include <sys/kstat.h>
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate #define	NIAGARA_MODNAME	"SUNW,UltraSPARC-T1"
40*0Sstevel@tonic-gate #define	NUM_OF_PICS	2
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate /*
43*0Sstevel@tonic-gate  * Data structure used to build array of event-names and pcr-mask values
44*0Sstevel@tonic-gate  */
45*0Sstevel@tonic-gate typedef struct ni_kev_mask {
46*0Sstevel@tonic-gate 	char		*event_name;
47*0Sstevel@tonic-gate 	uint64_t	pcr_mask;
48*0Sstevel@tonic-gate } ni_kev_mask_t;
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate /*
51*0Sstevel@tonic-gate  * Kstat data structure for DRAM and JBUS performance counters
52*0Sstevel@tonic-gate  *
53*0Sstevel@tonic-gate  * Note that these performance counters are only 31 bits wide. Since
54*0Sstevel@tonic-gate  * the "busstat" command assumes a 32-bit counter, we emulate a 32-bit
55*0Sstevel@tonic-gate  * counter by detecting overflow on read of these performance counters
56*0Sstevel@tonic-gate  * and using the least significant bit of the overflow count as the
57*0Sstevel@tonic-gate  * most significant bit (i.e. bit# 31) of the DRAM and JBUS performance
58*0Sstevel@tonic-gate  * counters.
59*0Sstevel@tonic-gate  */
60*0Sstevel@tonic-gate typedef struct ni_ksinfo {
61*0Sstevel@tonic-gate 	uint8_t		pic_no_evs;			/* number of events */
62*0Sstevel@tonic-gate 	uint8_t		pic_sel_shift[NUM_OF_PICS];
63*0Sstevel@tonic-gate 	uint8_t		pic_shift[NUM_OF_PICS];
64*0Sstevel@tonic-gate 	uint64_t	pic_mask[NUM_OF_PICS];
65*0Sstevel@tonic-gate 	kstat_t		*pic_name_ksp[NUM_OF_PICS];
66*0Sstevel@tonic-gate 	kstat_t		*cntr_ksp;
67*0Sstevel@tonic-gate 	uint32_t	pic_reg;
68*0Sstevel@tonic-gate 	uint32_t	pcr_reg;
69*0Sstevel@tonic-gate 	uint32_t	pic_overflow[NUM_OF_PICS];	/* overflow count */
70*0Sstevel@tonic-gate 	uint32_t	pic_last_val[NUM_OF_PICS];	/* last PIC value */
71*0Sstevel@tonic-gate } ni_ksinfo_t;
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate static ni_ksinfo_t	*ni_dram_kstats[NIAGARA_DRAM_BANKS];
74*0Sstevel@tonic-gate static ni_ksinfo_t	*ni_jbus_kstat;
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate typedef struct ni_perf_regs {
77*0Sstevel@tonic-gate 	uint32_t	pcr_reg;
78*0Sstevel@tonic-gate 	uint32_t	pic_reg;
79*0Sstevel@tonic-gate } ni_perf_regs_t;
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate static ni_perf_regs_t dram_perf_regs[] = {
82*0Sstevel@tonic-gate 	{HV_NIAGARA_DRAM_CTL0, HV_NIAGARA_DRAM_COUNT0},
83*0Sstevel@tonic-gate 	{HV_NIAGARA_DRAM_CTL1, HV_NIAGARA_DRAM_COUNT1},
84*0Sstevel@tonic-gate 	{HV_NIAGARA_DRAM_CTL2, HV_NIAGARA_DRAM_COUNT2},
85*0Sstevel@tonic-gate 	{HV_NIAGARA_DRAM_CTL3, HV_NIAGARA_DRAM_COUNT3},
86*0Sstevel@tonic-gate };
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate static void ni_create_name_kstat(char *, ni_ksinfo_t *, ni_kev_mask_t *);
90*0Sstevel@tonic-gate static void ni_delete_name_kstat(ni_ksinfo_t *);
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate static kstat_t *ni_create_cntr_kstat(char *, int,
93*0Sstevel@tonic-gate 	int (*update)(kstat_t *, int), void *);
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate static int ni_cntr_kstat_update(kstat_t *, int);
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate static kstat_t *ni_create_picN_kstat(char *, int, int, int,
98*0Sstevel@tonic-gate 	ni_kev_mask_t *);
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate #ifdef DEBUG
101*0Sstevel@tonic-gate static int	ni_perf_debug;
102*0Sstevel@tonic-gate #endif
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate /*
105*0Sstevel@tonic-gate  * Niagara DRAM Performance Events
106*0Sstevel@tonic-gate  */
107*0Sstevel@tonic-gate static ni_kev_mask_t
108*0Sstevel@tonic-gate niagara_dram_events[] = {
109*0Sstevel@tonic-gate 	{"mem_reads",		0x0},
110*0Sstevel@tonic-gate 	{"mem_writes",		0x1},
111*0Sstevel@tonic-gate 	{"mem_read_write",	0x2},
112*0Sstevel@tonic-gate 	{"bank_busy_stalls",	0x3},
113*0Sstevel@tonic-gate 	{"rd_queue_latency",	0x4},
114*0Sstevel@tonic-gate 	{"wr_queue_latency",	0x5},
115*0Sstevel@tonic-gate 	{"rw_queue_latency",	0x6},
116*0Sstevel@tonic-gate 	{"wb_buf_hits",		0x7},
117*0Sstevel@tonic-gate 	{"clear_pic", 0xf}
118*0Sstevel@tonic-gate };
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate /*
122*0Sstevel@tonic-gate  * Niagara JBUS Performance Events
123*0Sstevel@tonic-gate  */
124*0Sstevel@tonic-gate static ni_kev_mask_t
125*0Sstevel@tonic-gate niagara_jbus_events[] = {
126*0Sstevel@tonic-gate 	{"jbus_cycles",		0x1},
127*0Sstevel@tonic-gate 	{"dma_reads",		0x2},
128*0Sstevel@tonic-gate 	{"dma_read_latency",	0x3},
129*0Sstevel@tonic-gate 	{"dma_writes",		0x4},
130*0Sstevel@tonic-gate 	{"dma_write8",		0x5},
131*0Sstevel@tonic-gate 	{"ordering_waits",	0x6},
132*0Sstevel@tonic-gate 	{"pio_reads",		0x8},
133*0Sstevel@tonic-gate 	{"pio_read_latency",	0x9},
134*0Sstevel@tonic-gate 	{"aok_dok_off_cycles",	0xc},
135*0Sstevel@tonic-gate 	{"aok_off_cycles",	0xd},
136*0Sstevel@tonic-gate 	{"dok_off_cycles",	0xe},
137*0Sstevel@tonic-gate 	{"clear_pic",		0xf}
138*0Sstevel@tonic-gate };
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate /*
141*0Sstevel@tonic-gate  * Create the picN kstats for DRAM and JBUS events
142*0Sstevel@tonic-gate  */
143*0Sstevel@tonic-gate void
144*0Sstevel@tonic-gate niagara_kstat_init()
145*0Sstevel@tonic-gate {
146*0Sstevel@tonic-gate 	int i;
147*0Sstevel@tonic-gate 	ni_ksinfo_t *ksinfop;
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate #ifdef DEBUG
150*0Sstevel@tonic-gate 	if (ni_perf_debug)
151*0Sstevel@tonic-gate 		printf("ni_kstat_init called\n");
152*0Sstevel@tonic-gate #endif
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 	/*
155*0Sstevel@tonic-gate 	 * Create DRAM perf events kstat
156*0Sstevel@tonic-gate 	 */
157*0Sstevel@tonic-gate 	for (i = 0; i < NIAGARA_DRAM_BANKS; i++) {
158*0Sstevel@tonic-gate 		ksinfop = (ni_ksinfo_t *)kmem_zalloc(sizeof (ni_ksinfo_t),
159*0Sstevel@tonic-gate 		    KM_NOSLEEP);
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 		if (ksinfop == NULL) {
162*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
163*0Sstevel@tonic-gate 			    "%s: no space for niagara dram kstat\n",
164*0Sstevel@tonic-gate 			    NIAGARA_MODNAME);
165*0Sstevel@tonic-gate 			break;
166*0Sstevel@tonic-gate 		}
167*0Sstevel@tonic-gate 		ksinfop->pic_no_evs =
168*0Sstevel@tonic-gate 			sizeof (niagara_dram_events) / sizeof (ni_kev_mask_t);
169*0Sstevel@tonic-gate 		ksinfop->pic_sel_shift[0] = NIAGARA_DRAM_PIC0_SEL_SHIFT;
170*0Sstevel@tonic-gate 		ksinfop->pic_shift[0] = NIAGARA_DRAM_PIC0_SHIFT;
171*0Sstevel@tonic-gate 		ksinfop->pic_mask[0] = NIAGARA_DRAM_PIC0_MASK;
172*0Sstevel@tonic-gate 		ksinfop->pic_sel_shift[1] = NIAGARA_DRAM_PIC1_SEL_SHIFT;
173*0Sstevel@tonic-gate 		ksinfop->pic_shift[1] = NIAGARA_DRAM_PIC1_SHIFT;
174*0Sstevel@tonic-gate 		ksinfop->pic_mask[1] = NIAGARA_DRAM_PIC1_MASK;
175*0Sstevel@tonic-gate 		ksinfop->pic_reg = dram_perf_regs[i].pic_reg;
176*0Sstevel@tonic-gate 		ksinfop->pcr_reg = dram_perf_regs[i].pcr_reg;
177*0Sstevel@tonic-gate 		ni_dram_kstats[i] = ksinfop;
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate 		/* create basic pic event/mask pair (only once) */
180*0Sstevel@tonic-gate 		if (i == 0)
181*0Sstevel@tonic-gate 			ni_create_name_kstat("dram", ksinfop,
182*0Sstevel@tonic-gate 				    niagara_dram_events);
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 		/* create counter kstats */
185*0Sstevel@tonic-gate 		ni_dram_kstats[i]->cntr_ksp = ni_create_cntr_kstat("dram", i,
186*0Sstevel@tonic-gate 		    ni_cntr_kstat_update, ksinfop);
187*0Sstevel@tonic-gate 	}
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	/*
190*0Sstevel@tonic-gate 	 * Create JBUS perf events kstat
191*0Sstevel@tonic-gate 	 */
192*0Sstevel@tonic-gate 	ni_jbus_kstat = (ni_ksinfo_t *)kmem_alloc(sizeof (ni_ksinfo_t),
193*0Sstevel@tonic-gate 		KM_NOSLEEP);
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	if (ni_jbus_kstat == NULL) {
196*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: no space for niagara jbus kstat\n",
197*0Sstevel@tonic-gate 		    NIAGARA_MODNAME);
198*0Sstevel@tonic-gate 	} else {
199*0Sstevel@tonic-gate 		ni_jbus_kstat->pic_no_evs =
200*0Sstevel@tonic-gate 			sizeof (niagara_jbus_events) / sizeof (ni_kev_mask_t);
201*0Sstevel@tonic-gate 		ni_jbus_kstat->pic_sel_shift[0] = NIAGARA_JBUS_PIC0_SEL_SHIFT;
202*0Sstevel@tonic-gate 		ni_jbus_kstat->pic_shift[0] = NIAGARA_JBUS_PIC0_SHIFT;
203*0Sstevel@tonic-gate 		ni_jbus_kstat->pic_mask[0] = NIAGARA_JBUS_PIC0_MASK;
204*0Sstevel@tonic-gate 		ni_jbus_kstat->pic_sel_shift[1] = NIAGARA_JBUS_PIC1_SEL_SHIFT;
205*0Sstevel@tonic-gate 		ni_jbus_kstat->pic_shift[1] = NIAGARA_JBUS_PIC1_SHIFT;
206*0Sstevel@tonic-gate 		ni_jbus_kstat->pic_mask[1] = NIAGARA_JBUS_PIC1_MASK;
207*0Sstevel@tonic-gate 		ni_jbus_kstat->pic_reg = HV_NIAGARA_JBUS_COUNT;
208*0Sstevel@tonic-gate 		ni_jbus_kstat->pcr_reg = HV_NIAGARA_JBUS_CTL;
209*0Sstevel@tonic-gate 		ni_create_name_kstat("jbus", ni_jbus_kstat,
210*0Sstevel@tonic-gate 		    niagara_jbus_events);
211*0Sstevel@tonic-gate 		ni_jbus_kstat->cntr_ksp = ni_create_cntr_kstat("jbus", 0,
212*0Sstevel@tonic-gate 		    ni_cntr_kstat_update, ni_jbus_kstat);
213*0Sstevel@tonic-gate 	}
214*0Sstevel@tonic-gate }
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate void
217*0Sstevel@tonic-gate niagara_kstat_fini()
218*0Sstevel@tonic-gate {
219*0Sstevel@tonic-gate 	int i;
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate #ifdef DEBUG
222*0Sstevel@tonic-gate 	if (ni_perf_debug)
223*0Sstevel@tonic-gate 		printf("ni_kstat_fini called\n");
224*0Sstevel@tonic-gate #endif
225*0Sstevel@tonic-gate 	for (i = 0; i < NIAGARA_DRAM_BANKS; i++) {
226*0Sstevel@tonic-gate 		if (ni_dram_kstats[i] != NULL) {
227*0Sstevel@tonic-gate 			ni_delete_name_kstat(ni_dram_kstats[i]);
228*0Sstevel@tonic-gate 			if (ni_dram_kstats[i]->cntr_ksp != NULL)
229*0Sstevel@tonic-gate 				kstat_delete(ni_dram_kstats[i]->cntr_ksp);
230*0Sstevel@tonic-gate 			kmem_free(ni_dram_kstats[i], sizeof (ni_ksinfo_t));
231*0Sstevel@tonic-gate 			ni_dram_kstats[i] = NULL;
232*0Sstevel@tonic-gate 		}
233*0Sstevel@tonic-gate 	}
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	if (ni_jbus_kstat != NULL) {
236*0Sstevel@tonic-gate 		ni_delete_name_kstat(ni_jbus_kstat);
237*0Sstevel@tonic-gate 		if (ni_jbus_kstat->cntr_ksp != NULL)
238*0Sstevel@tonic-gate 			kstat_delete(ni_jbus_kstat->cntr_ksp);
239*0Sstevel@tonic-gate 		kmem_free(ni_jbus_kstat, sizeof (ni_ksinfo_t));
240*0Sstevel@tonic-gate 		ni_jbus_kstat = NULL;
241*0Sstevel@tonic-gate 	}
242*0Sstevel@tonic-gate }
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate static void
245*0Sstevel@tonic-gate ni_create_name_kstat(char *name, ni_ksinfo_t *pp, ni_kev_mask_t *ev)
246*0Sstevel@tonic-gate {
247*0Sstevel@tonic-gate 	int	i;
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate #ifdef DEBUG
250*0Sstevel@tonic-gate 	if (ni_perf_debug > 1)
251*0Sstevel@tonic-gate 		printf("ni_create_name_kstat: name: %s\n", name);
252*0Sstevel@tonic-gate #endif
253*0Sstevel@tonic-gate 	for (i = 0; i < NUM_OF_PICS; i++) {
254*0Sstevel@tonic-gate 		pp->pic_name_ksp[i] = ni_create_picN_kstat(name,
255*0Sstevel@tonic-gate 			i, pp->pic_sel_shift[i], pp->pic_no_evs, ev);
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 		if (pp->pic_name_ksp[i] == NULL) {
258*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s: unable to create name kstat",
259*0Sstevel@tonic-gate 			    NIAGARA_MODNAME);
260*0Sstevel@tonic-gate 		}
261*0Sstevel@tonic-gate 	}
262*0Sstevel@tonic-gate }
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate static void
265*0Sstevel@tonic-gate ni_delete_name_kstat(ni_ksinfo_t *pp)
266*0Sstevel@tonic-gate {
267*0Sstevel@tonic-gate 	int	i;
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	if (pp != NULL) {
270*0Sstevel@tonic-gate 		for (i = 0; i < NUM_OF_PICS; i++) {
271*0Sstevel@tonic-gate 			if (pp->pic_name_ksp[i] != NULL)
272*0Sstevel@tonic-gate 				kstat_delete(pp->pic_name_ksp[i]);
273*0Sstevel@tonic-gate 		}
274*0Sstevel@tonic-gate 	}
275*0Sstevel@tonic-gate }
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate /*
278*0Sstevel@tonic-gate  * Create the picN kstat. Returns a pointer to the
279*0Sstevel@tonic-gate  * kstat which the driver must store to allow it
280*0Sstevel@tonic-gate  * to be deleted when necessary.
281*0Sstevel@tonic-gate  */
282*0Sstevel@tonic-gate static kstat_t *
283*0Sstevel@tonic-gate ni_create_picN_kstat(char *mod_name, int pic, int pic_sel_shift,
284*0Sstevel@tonic-gate 	int num_ev, ni_kev_mask_t *ev_array)
285*0Sstevel@tonic-gate {
286*0Sstevel@tonic-gate 	struct kstat_named *pic_named_data;
287*0Sstevel@tonic-gate 	int	inst = 0;
288*0Sstevel@tonic-gate 	int	event;
289*0Sstevel@tonic-gate 	char	pic_name[30];
290*0Sstevel@tonic-gate 	kstat_t	*picN_ksp = NULL;
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 	(void) sprintf(pic_name, "pic%d", pic);
293*0Sstevel@tonic-gate 	if ((picN_ksp = kstat_create(mod_name, inst, pic_name,
294*0Sstevel@tonic-gate 	    "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) {
295*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s %s : kstat create failed",
296*0Sstevel@tonic-gate 			mod_name, pic_name);
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 		/*
299*0Sstevel@tonic-gate 		 * It is up to the calling function to delete any kstats
300*0Sstevel@tonic-gate 		 * that may have been created already. We just
301*0Sstevel@tonic-gate 		 * return NULL to indicate an error has occured.
302*0Sstevel@tonic-gate 		 */
303*0Sstevel@tonic-gate 		return (NULL);
304*0Sstevel@tonic-gate 	}
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	pic_named_data = (struct kstat_named *)
307*0Sstevel@tonic-gate 	    picN_ksp->ks_data;
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	/*
310*0Sstevel@tonic-gate 	 * Write event names and their associated pcr masks. The
311*0Sstevel@tonic-gate 	 * last entry in the array (clear_pic) is added seperately
312*0Sstevel@tonic-gate 	 * below as the pic value must be inverted.
313*0Sstevel@tonic-gate 	 */
314*0Sstevel@tonic-gate 	for (event = 0; event < num_ev - 1; event++) {
315*0Sstevel@tonic-gate 		pic_named_data[event].value.ui64 =
316*0Sstevel@tonic-gate 			(ev_array[event].pcr_mask << pic_sel_shift);
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 		kstat_named_init(&pic_named_data[event],
319*0Sstevel@tonic-gate 			ev_array[event].event_name,
320*0Sstevel@tonic-gate 			KSTAT_DATA_UINT64);
321*0Sstevel@tonic-gate 	}
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 	/*
324*0Sstevel@tonic-gate 	 * add the clear_pic entry.
325*0Sstevel@tonic-gate 	 */
326*0Sstevel@tonic-gate 	pic_named_data[event].value.ui64 =
327*0Sstevel@tonic-gate 		(uint64_t)~(ev_array[event].pcr_mask << pic_sel_shift);
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	kstat_named_init(&pic_named_data[event], ev_array[event].event_name,
330*0Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	kstat_install(picN_ksp);
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 	return (picN_ksp);
335*0Sstevel@tonic-gate }
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate /*
338*0Sstevel@tonic-gate  * Create the "counters" kstat.
339*0Sstevel@tonic-gate  */
340*0Sstevel@tonic-gate static kstat_t *
341*0Sstevel@tonic-gate ni_create_cntr_kstat(char *name, int instance, int (*update)(kstat_t *, int),
342*0Sstevel@tonic-gate 	void *ksinfop)
343*0Sstevel@tonic-gate {
344*0Sstevel@tonic-gate 	struct kstat	*counters_ksp;
345*0Sstevel@tonic-gate 	struct kstat_named	*counters_named_data;
346*0Sstevel@tonic-gate 	char		pic_str[10];
347*0Sstevel@tonic-gate 	int		i;
348*0Sstevel@tonic-gate 	int		num_pics = NUM_OF_PICS;
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate #ifdef DEBUG
351*0Sstevel@tonic-gate 	if (ni_perf_debug > 1)
352*0Sstevel@tonic-gate 		printf("ni_create_cntr_kstat: name: %s instance: %d\n",
353*0Sstevel@tonic-gate 		    name, instance);
354*0Sstevel@tonic-gate #endif
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 	/*
357*0Sstevel@tonic-gate 	 * Size of kstat is num_pics + 1 as it
358*0Sstevel@tonic-gate 	 * also contains the %pcr
359*0Sstevel@tonic-gate 	 */
360*0Sstevel@tonic-gate 	if ((counters_ksp = kstat_create(name, instance, "counters", "bus",
361*0Sstevel@tonic-gate 	    KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) {
362*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
363*0Sstevel@tonic-gate 		    "%s: kstat_create for %s%d failed", NIAGARA_MODNAME,
364*0Sstevel@tonic-gate 		    name, instance);
365*0Sstevel@tonic-gate 		return (NULL);
366*0Sstevel@tonic-gate 	}
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	counters_named_data = (struct kstat_named *)(counters_ksp->ks_data);
369*0Sstevel@tonic-gate 
370*0Sstevel@tonic-gate 	/*
371*0Sstevel@tonic-gate 	 * Iinitialize the named kstats
372*0Sstevel@tonic-gate 	 */
373*0Sstevel@tonic-gate 	kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64);
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	for (i = 0; i < num_pics; i++) {
376*0Sstevel@tonic-gate 		(void) sprintf(pic_str, "pic%d", i);
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 		kstat_named_init(&counters_named_data[i+1], pic_str,
379*0Sstevel@tonic-gate 		    KSTAT_DATA_UINT64);
380*0Sstevel@tonic-gate 	}
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate 	/*
383*0Sstevel@tonic-gate 	 * Store the register offset's in the kstat's
384*0Sstevel@tonic-gate 	 * private field so that they are available
385*0Sstevel@tonic-gate 	 * to the update function.
386*0Sstevel@tonic-gate 	 */
387*0Sstevel@tonic-gate 	counters_ksp->ks_private = (void *)ksinfop;
388*0Sstevel@tonic-gate 	counters_ksp->ks_update = update;
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 	kstat_install(counters_ksp);
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	return (counters_ksp);
393*0Sstevel@tonic-gate }
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate /*
396*0Sstevel@tonic-gate  * kstat update function. Handles reads/writes
397*0Sstevel@tonic-gate  * from/to kstat.
398*0Sstevel@tonic-gate  */
399*0Sstevel@tonic-gate static int
400*0Sstevel@tonic-gate ni_cntr_kstat_update(kstat_t *ksp, int rw)
401*0Sstevel@tonic-gate {
402*0Sstevel@tonic-gate 	struct kstat_named	*data_p;
403*0Sstevel@tonic-gate 	ni_ksinfo_t	*ksinfop = ksp->ks_private;
404*0Sstevel@tonic-gate 	uint64_t	pic, pcr;
405*0Sstevel@tonic-gate 	int		stat = 0;
406*0Sstevel@tonic-gate 	uint32_t	pic0, pic1;
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 	data_p = (struct kstat_named *)ksp->ks_data;
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	if (rw == KSTAT_WRITE) {
411*0Sstevel@tonic-gate #ifdef DEBUG
412*0Sstevel@tonic-gate 		if (ni_perf_debug)
413*0Sstevel@tonic-gate 			printf("ni_cntr_kstat_update: wr pcr-%d: %llx\n",
414*0Sstevel@tonic-gate 			    ksinfop->pcr_reg, data_p[0].value.ui64);
415*0Sstevel@tonic-gate #endif
416*0Sstevel@tonic-gate 		if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64))
417*0Sstevel@tonic-gate 			stat = EACCES;
418*0Sstevel@tonic-gate 	} else {
419*0Sstevel@tonic-gate 		if (hv_niagara_getperf(ksinfop->pic_reg, &pic) != 0 ||
420*0Sstevel@tonic-gate 		    hv_niagara_getperf(ksinfop->pcr_reg, &pcr) != 0)
421*0Sstevel@tonic-gate 			stat = EACCES;
422*0Sstevel@tonic-gate 		else {
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 			data_p[0].value.ui64 = pcr;
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 			/*
427*0Sstevel@tonic-gate 			 * Generate a 32-bit PIC0 value by detecting overflow
428*0Sstevel@tonic-gate 			 */
429*0Sstevel@tonic-gate 			pic0 = (uint32_t)((pic >> ksinfop->pic_shift[0]) &
430*0Sstevel@tonic-gate 			    ksinfop->pic_mask[0]);
431*0Sstevel@tonic-gate 			if (pic0 < ksinfop->pic_last_val[0])
432*0Sstevel@tonic-gate 				ksinfop->pic_overflow[0]++;
433*0Sstevel@tonic-gate 			ksinfop->pic_last_val[0] = pic0;
434*0Sstevel@tonic-gate 			pic0 += (ksinfop->pic_overflow[0] & 1) << 31;
435*0Sstevel@tonic-gate 			data_p[1].value.ui64 = (uint64_t)pic0;
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 			/*
438*0Sstevel@tonic-gate 			 * Generate a 32-bit PIC1 value by detecting overflow
439*0Sstevel@tonic-gate 			 */
440*0Sstevel@tonic-gate 			pic1 = (uint32_t)((pic >> ksinfop->pic_shift[1]) &
441*0Sstevel@tonic-gate 			    ksinfop->pic_mask[1]);
442*0Sstevel@tonic-gate 			if (pic1 < ksinfop->pic_last_val[1])
443*0Sstevel@tonic-gate 				ksinfop->pic_overflow[1]++;
444*0Sstevel@tonic-gate 			ksinfop->pic_last_val[1] = pic1;
445*0Sstevel@tonic-gate 			pic1 += (ksinfop->pic_overflow[1] & 1) << 31;
446*0Sstevel@tonic-gate 			data_p[2].value.ui64 = (uint64_t)pic1;
447*0Sstevel@tonic-gate 		}
448*0Sstevel@tonic-gate #ifdef DEBUG
449*0Sstevel@tonic-gate 		if (ni_perf_debug)
450*0Sstevel@tonic-gate 			printf("ni_cntr_kstat_update: rd pcr%d: %lx  "
451*0Sstevel@tonic-gate 			    "pic%d: %16lx pic0: %8lx pic1: %8lx\n",
452*0Sstevel@tonic-gate 			    ksinfop->pcr_reg, pcr, ksinfop->pic_reg, pic,
453*0Sstevel@tonic-gate 			    data_p[1].value.ui64, data_p[2].value.ui64);
454*0Sstevel@tonic-gate #endif
455*0Sstevel@tonic-gate 	}
456*0Sstevel@tonic-gate 	return (stat);
457*0Sstevel@tonic-gate }
458