xref: /titanic_44/usr/src/uts/sun4v/cpu/niagara_perfctr.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 #include <sys/types.h>
29 #include <sys/async.h>
30 #include <sys/sunddi.h>
31 #include <sys/sunndi.h>
32 #include <sys/ddi_impldefs.h>
33 #include <sys/machsystm.h>
34 #include <sys/hypervisor_api.h>
35 #include <sys/kstat.h>
36 #if defined(NIAGARA_IMPL)
37 #include <sys/niagararegs.h>
38 #elif defined(NIAGARA2_IMPL) || defined(VFALLS_IMPL)
39 #include <sys/niagara2regs.h>
40 #endif
41 
42 extern char cpu_module_name[];
43 
44 /*
45  * Data structure used to build array of event-names and pcr-mask values
46  */
47 typedef struct ni_kev_mask {
48 	char		*event_name;
49 	uint64_t	pcr_mask;
50 } ni_kev_mask_t;
51 
52 /*
53  * Kstat data structure for DRAM and JBUS performance counters
54  *
55  * Note that these performance counters are only 31 bits wide. Since
56  * the "busstat" command assumes a 32-bit counter, we emulate a 32-bit
57  * counter by detecting overflow on read of these performance counters
58  * and using the least significant bit of the overflow count as the
59  * most significant bit (i.e. bit# 31) of the DRAM and JBUS performance
60  * counters.
61  */
62 #define	NUM_OF_PICS	2
63 
64 typedef struct ni_ksinfo {
65 	uint8_t		pic_no_evs;			/* number of events */
66 	uint8_t		pic_sel_shift[NUM_OF_PICS];
67 	uint8_t		pic_shift[NUM_OF_PICS];
68 	uint64_t	pic_mask[NUM_OF_PICS];
69 	kstat_t		*pic_name_ksp[NUM_OF_PICS];
70 	kstat_t		*cntr_ksp;
71 	uint32_t	pic_reg[NUM_OF_PICS];
72 	uint32_t	pcr_reg;
73 	uint32_t	pic_overflow[NUM_OF_PICS];	/* overflow count */
74 	uint32_t	pic_last_val[NUM_OF_PICS];	/* last PIC value */
75 } ni_ksinfo_t;
76 
77 static ni_ksinfo_t	*ni_dram_kstats[NIAGARA_DRAM_BANKS];
78 
79 #if defined(NIAGARA_IMPL)
80 static ni_ksinfo_t	*ni_jbus_kstat;
81 #endif
82 
83 typedef struct ni_perf_regs {
84 	uint32_t	pcr_reg;
85 	uint32_t	pic_reg;
86 } ni_perf_regs_t;
87 
88 static ni_perf_regs_t dram_perf_regs[] = {
89 	{HV_NIAGARA_DRAM_CTL0, HV_NIAGARA_DRAM_COUNT0},
90 	{HV_NIAGARA_DRAM_CTL1, HV_NIAGARA_DRAM_COUNT1},
91 	{HV_NIAGARA_DRAM_CTL2, HV_NIAGARA_DRAM_COUNT2},
92 	{HV_NIAGARA_DRAM_CTL3, HV_NIAGARA_DRAM_COUNT3},
93 #ifdef VFALLS_IMPL
94 	{HV_NIAGARA_DRAM_CTL4, HV_NIAGARA_DRAM_COUNT4},
95 	{HV_NIAGARA_DRAM_CTL5, HV_NIAGARA_DRAM_COUNT5},
96 	{HV_NIAGARA_DRAM_CTL6, HV_NIAGARA_DRAM_COUNT6},
97 	{HV_NIAGARA_DRAM_CTL7, HV_NIAGARA_DRAM_COUNT7}
98 #endif
99 };
100 
101 #ifdef VFALLS_IMPL
102 /*
103  * Kstat data structure for Zambezi performance counters
104  * These performance counters are 64 bits wide.
105  */
106 static ni_ksinfo_t	*zam_lpu_kstats[ZAMBEZI_LPU_COUNTERS];
107 static ni_ksinfo_t	*zam_gpd_kstats[ZAMBEZI_GPD_COUNTERS];
108 static ni_ksinfo_t	*zam_asu_kstats[ZAMBEZI_ASU_COUNTERS];
109 
110 typedef struct zam_perf_regs {
111 	uint32_t	pcr_reg;
112 	uint32_t	pic_reg[NUM_OF_PICS];
113 } zam_perf_regs_t;
114 
115 static zam_perf_regs_t lpu_perf_regs[] = {
116 	{HV_ZAM0_LPU_A_PCR, HV_ZAM0_LPU_A_PIC0, HV_ZAM0_LPU_A_PIC1},
117 	{HV_ZAM0_LPU_B_PCR, HV_ZAM0_LPU_B_PIC0, HV_ZAM0_LPU_B_PIC1},
118 	{HV_ZAM0_LPU_C_PCR, HV_ZAM0_LPU_C_PIC0, HV_ZAM0_LPU_C_PIC1},
119 	{HV_ZAM0_LPU_D_PCR, HV_ZAM0_LPU_D_PIC0, HV_ZAM0_LPU_D_PIC1},
120 
121 	{HV_ZAM1_LPU_A_PCR, HV_ZAM1_LPU_A_PIC0, HV_ZAM1_LPU_A_PIC1},
122 	{HV_ZAM1_LPU_B_PCR, HV_ZAM1_LPU_B_PIC0, HV_ZAM1_LPU_B_PIC1},
123 	{HV_ZAM1_LPU_C_PCR, HV_ZAM1_LPU_C_PIC0, HV_ZAM1_LPU_C_PIC1},
124 	{HV_ZAM1_LPU_D_PCR, HV_ZAM1_LPU_D_PIC0, HV_ZAM1_LPU_D_PIC1},
125 
126 	{HV_ZAM2_LPU_A_PCR, HV_ZAM2_LPU_A_PIC0, HV_ZAM2_LPU_A_PIC1},
127 	{HV_ZAM2_LPU_B_PCR, HV_ZAM2_LPU_B_PIC0, HV_ZAM2_LPU_B_PIC1},
128 	{HV_ZAM2_LPU_C_PCR, HV_ZAM2_LPU_C_PIC0, HV_ZAM2_LPU_C_PIC1},
129 	{HV_ZAM2_LPU_D_PCR, HV_ZAM2_LPU_D_PIC0, HV_ZAM2_LPU_D_PIC1},
130 
131 	{HV_ZAM3_LPU_A_PCR, HV_ZAM3_LPU_A_PIC0, HV_ZAM3_LPU_A_PIC1},
132 	{HV_ZAM3_LPU_B_PCR, HV_ZAM3_LPU_B_PIC0, HV_ZAM3_LPU_B_PIC1},
133 	{HV_ZAM3_LPU_C_PCR, HV_ZAM3_LPU_C_PIC0, HV_ZAM3_LPU_C_PIC1},
134 	{HV_ZAM3_LPU_D_PCR, HV_ZAM3_LPU_D_PIC0, HV_ZAM3_LPU_D_PIC1}
135 };
136 
137 static zam_perf_regs_t gpd_perf_regs[] = {
138 	{HV_ZAM0_GPD_PCR, HV_ZAM0_GPD_PIC0, HV_ZAM0_GPD_PIC1},
139 	{HV_ZAM1_GPD_PCR, HV_ZAM1_GPD_PIC0, HV_ZAM1_GPD_PIC1},
140 	{HV_ZAM2_GPD_PCR, HV_ZAM2_GPD_PIC0, HV_ZAM2_GPD_PIC1},
141 	{HV_ZAM3_GPD_PCR, HV_ZAM3_GPD_PIC0, HV_ZAM3_GPD_PIC1}
142 };
143 
144 static zam_perf_regs_t asu_perf_regs[] = {
145 	{HV_ZAM0_ASU_PCR, HV_ZAM0_ASU_PIC0, HV_ZAM0_ASU_PIC1},
146 	{HV_ZAM1_ASU_PCR, HV_ZAM1_ASU_PIC0, HV_ZAM1_ASU_PIC1},
147 	{HV_ZAM2_ASU_PCR, HV_ZAM2_ASU_PIC0, HV_ZAM2_ASU_PIC1},
148 	{HV_ZAM3_ASU_PCR, HV_ZAM3_ASU_PIC0, HV_ZAM3_ASU_PIC1}
149 };
150 
151 static int zam_cntr_kstat_update(kstat_t *, int);
152 #endif
153 
154 static void ni_create_name_kstat(char *, ni_ksinfo_t *, ni_kev_mask_t *);
155 static void ni_delete_name_kstat(ni_ksinfo_t *);
156 
157 static kstat_t *ni_create_cntr_kstat(char *, int,
158 	int (*update)(kstat_t *, int), void *);
159 
160 static int ni_cntr_kstat_update(kstat_t *, int);
161 
162 static kstat_t *ni_create_picN_kstat(char *, int, int, int,
163 	ni_kev_mask_t *);
164 
165 #ifdef DEBUG
166 static int	ni_perf_debug;
167 #endif
168 
169 /*
170  * Niagara, Niagara2 and VFalls DRAM Performance Events
171  */
172 static ni_kev_mask_t
173 niagara_dram_events[] = {
174 	{"mem_reads",		0x0},
175 	{"mem_writes",		0x1},
176 	{"mem_read_write",	0x2},
177 	{"bank_busy_stalls",	0x3},
178 	{"rd_queue_latency",	0x4},
179 	{"wr_queue_latency",	0x5},
180 	{"rw_queue_latency",	0x6},
181 	{"wb_buf_hits",		0x7},
182 	{"clear_pic",		0xf}
183 };
184 
185 #if defined(VFALLS_IMPL)
186 /*
187  * Zambezi Performance Events
188  */
189 static ni_kev_mask_t
190 zam_lpu_perf_events[] = {
191 	{"none",		0x0},
192 	{"clock_cycles",	0x1},
193 	{"cycles_c2c_portX",	0x2},
194 	{"cycles_mem_portX",	0x3},
195 	{"cycles_WB_portX",	0x4},
196 	{"cycles_NC_portX",	0x5},
197 	{"cycles_c2c_portY",	0x6},
198 	{"cycles_mem_portY",	0x7},
199 	{"cycles_WB_portY",	0x8},
200 	{"cycles_NC_portY",	0x9},
201 	{"cycles_c2c_portZ",	0xa},
202 	{"cycles_mem_portZ",	0xb},
203 	{"cycles_WB_portZ",	0xc},
204 	{"cycles_NC_portZ",	0xd},
205 	{"cycles_TID_WB",	0xe},
206 	{"cycles_TID_INV",	0xf},
207 	{"cycles_TID_RTD",	0x10},
208 	{"cycles_TID_RTO",	0x11},
209 	{"cycles_TID_RTS",	0x12},
210 	{"cycles_IO_WRM",	0x13},
211 	{"cycles_IO_RD",	0x14},
212 	{"cycles_WB_egress",	0x15},
213 	{"cycles_INV_egress",	0x16},
214 	{"cycles_RTO_egress",	0x17},
215 	{"cycles_RTD_egress",	0x18},
216 	{"cycles_RTS_egress",	0x19},
217 	{"cycles_no_WB",	0x1a},
218 	{"cycles_no_read/inv",	0x1b},
219 	{"cycles_HIT_M",	0x1c},
220 	{"cycles_HIT_O",	0x1d},
221 	{"cycles_HIT_S",	0x1e},
222 	{"cycles_WB_HIT",	0x1f},
223 	{"cycles_MISS",		0x20},
224 	{"cycles_READ_or_INV",	0x21},
225 	{"cycles_WB",		0x22},
226 	{"cycles_NDR",		0x23},
227 	{"cycles_cache_miss",	0x24},
228 	{"cycles_cache_hit",	0x25},
229 	{"cycles_CRC_errors",	0x26},
230 	{"cycles_replys_sent",	0x27},
231 	{"cycles_replys_recev",	0x28},
232 	{"cycles_link_retrain",	0x29},
233 	{"clear_pic",		0xff}
234 };
235 
236 static ni_kev_mask_t
237 zam_gpd_perf_events[] = {
238 	{"none",		0x0},
239 	{"clock_cycles",	0x1},
240 	{"clear_pic",		0xf}
241 };
242 
243 static ni_kev_mask_t
244 zam_asu_perf_events[] = {
245 	{"none",		0x0},
246 	{"clock_cycles",	0x1},
247 	{"asu_in_pck",		0x2},
248 	{"asu_out_pck",		0x3},
249 	{"asu_CAM_hit",		0x4},
250 	{"asu_wakeup",		0x5},
251 	{"clear_pic",		0xf}
252 };
253 #endif
254 
255 #if defined(NIAGARA_IMPL)
256 /*
257  * Niagara JBUS Performance Events
258  */
259 static ni_kev_mask_t
260 niagara_jbus_events[] = {
261 	{"jbus_cycles",		0x1},
262 	{"dma_reads",		0x2},
263 	{"dma_read_latency",	0x3},
264 	{"dma_writes",		0x4},
265 	{"dma_write8",		0x5},
266 	{"ordering_waits",	0x6},
267 	{"pio_reads",		0x8},
268 	{"pio_read_latency",	0x9},
269 	{"aok_dok_off_cycles",	0xc},
270 	{"aok_off_cycles",	0xd},
271 	{"dok_off_cycles",	0xe},
272 	{"clear_pic",		0xf}
273 };
274 #endif
275 
276 /*
277  * Create the picN kstats for DRAM, JBUS and Zambezi events
278  */
279 void
280 niagara_kstat_init()
281 {
282 	int i;
283 	ni_ksinfo_t *ksinfop;
284 #ifdef VFALLS_IMPL
285 	uint64_t stat, pcr;
286 #endif
287 
288 #ifdef DEBUG
289 	if (ni_perf_debug)
290 		printf("ni_kstat_init called\n");
291 #endif
292 
293 	/*
294 	 * Create DRAM perf events kstat
295 	 */
296 	for (i = 0; i < NIAGARA_DRAM_BANKS; i++) {
297 #ifdef VFALLS_IMPL
298 		/* check if this dram instance is enabled in the HW */
299 		stat = hv_niagara_getperf(dram_perf_regs[i].pcr_reg, &pcr);
300 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
301 #endif
302 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
303 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
304 
305 			if (ksinfop == NULL) {
306 				cmn_err(CE_WARN,
307 				    "%s: no space for dram kstat\n",
308 				    cpu_module_name);
309 				break;
310 			}
311 			ksinfop->pic_no_evs =
312 			    sizeof (niagara_dram_events) /
313 			    sizeof (ni_kev_mask_t);
314 			ksinfop->pic_sel_shift[0] = NIAGARA_DRAM_PIC0_SEL_SHIFT;
315 			ksinfop->pic_shift[0] = NIAGARA_DRAM_PIC0_SHIFT;
316 			ksinfop->pic_mask[0] = NIAGARA_DRAM_PIC0_MASK;
317 			ksinfop->pic_sel_shift[1] = NIAGARA_DRAM_PIC1_SEL_SHIFT;
318 			ksinfop->pic_shift[1] = NIAGARA_DRAM_PIC1_SHIFT;
319 			ksinfop->pic_mask[1] = NIAGARA_DRAM_PIC1_MASK;
320 			ksinfop->pic_reg[0] = dram_perf_regs[i].pic_reg;
321 			ksinfop->pcr_reg = dram_perf_regs[i].pcr_reg;
322 			ni_dram_kstats[i] = ksinfop;
323 
324 			/* create basic pic event/mask pair (only once) */
325 			if (i == 0)
326 				ni_create_name_kstat("dram", ksinfop,
327 				    niagara_dram_events);
328 
329 			/* create counter kstats */
330 			ni_dram_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
331 			    "dram", i, ni_cntr_kstat_update, ksinfop);
332 #ifdef VFALLS_IMPL
333 		}
334 #endif
335 	}
336 
337 #ifdef VFALLS_IMPL
338 	/*
339 	 * Create Zambezi LPU perf events kstat
340 	 */
341 	for (i = 0; i < ZAMBEZI_LPU_COUNTERS; i++) {
342 		/* check if this Zambezi LPU instance is enabled in the HW */
343 		stat = hv_niagara_getperf(lpu_perf_regs[i].pcr_reg, &pcr);
344 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
345 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
346 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
347 
348 			if (ksinfop == NULL) {
349 				cmn_err(CE_WARN,
350 				    "%s: no space for zambezi lpu kstat\n",
351 				    cpu_module_name);
352 				break;
353 			}
354 			ksinfop->pic_no_evs =
355 			    sizeof (zam_lpu_perf_events) /
356 			    sizeof (ni_kev_mask_t);
357 			ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
358 			ksinfop->pic_reg[0] = lpu_perf_regs[i].pic_reg[0];
359 			ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
360 			ksinfop->pic_reg[1] = lpu_perf_regs[i].pic_reg[1];
361 			ksinfop->pcr_reg = lpu_perf_regs[i].pcr_reg;
362 			zam_lpu_kstats[i] = ksinfop;
363 
364 			/* create basic pic event/mask pair (only once) */
365 			if (i == 0)
366 				ni_create_name_kstat("lpu", ksinfop,
367 				    zam_lpu_perf_events);
368 
369 			/* create counter kstats */
370 			zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
371 			    "lpu", i, zam_cntr_kstat_update, ksinfop);
372 		}
373 	}
374 	/*
375 	 * Create Zambezi GPD perf events kstat
376 	 */
377 	for (i = 0; i < ZAMBEZI_GPD_COUNTERS; i++) {
378 		/* check if this Zambezi GPD instance is enabled in the HW */
379 		stat = hv_niagara_getperf(gpd_perf_regs[i].pcr_reg, &pcr);
380 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
381 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
382 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
383 
384 			if (ksinfop == NULL) {
385 				cmn_err(CE_WARN,
386 				    "%s: no space for zambezi gpd kstat\n",
387 				    cpu_module_name);
388 				break;
389 			}
390 			ksinfop->pic_no_evs =
391 			    sizeof (zam_gpd_perf_events) /
392 			    sizeof (ni_kev_mask_t);
393 			ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
394 			ksinfop->pic_reg[0] = gpd_perf_regs[i].pic_reg[0];
395 			ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
396 			ksinfop->pic_reg[1] = gpd_perf_regs[i].pic_reg[1];
397 			ksinfop->pcr_reg = gpd_perf_regs[i].pcr_reg;
398 			zam_gpd_kstats[i] = ksinfop;
399 
400 			/* create basic pic event/mask pair (only once) */
401 			if (i == 0)
402 				ni_create_name_kstat("gpd", ksinfop,
403 				    zam_gpd_perf_events);
404 
405 			/* create counter kstats */
406 			zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
407 			    "gpd", i, zam_cntr_kstat_update, ksinfop);
408 		}
409 	}
410 	/*
411 	 * Create Zambezi ASU perf events kstat
412 	 */
413 	for (i = 0; i < ZAMBEZI_ASU_COUNTERS; i++) {
414 		/* check if this Zambezi ASU instance is enabled in the HW */
415 		stat = hv_niagara_getperf(asu_perf_regs[i].pcr_reg, &pcr);
416 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
417 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
418 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
419 
420 			if (ksinfop == NULL) {
421 				cmn_err(CE_WARN,
422 				    "%s: no space for zambezi asu kstat\n",
423 				    cpu_module_name);
424 				break;
425 			}
426 			ksinfop->pic_no_evs =
427 			    sizeof (zam_asu_perf_events) /
428 			    sizeof (ni_kev_mask_t);
429 			ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
430 			ksinfop->pic_reg[0] = asu_perf_regs[i].pic_reg[0];
431 			ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
432 			ksinfop->pic_reg[1] = asu_perf_regs[i].pic_reg[1];
433 			ksinfop->pcr_reg = asu_perf_regs[i].pcr_reg;
434 			zam_asu_kstats[i] = ksinfop;
435 
436 			/* create basic pic event/mask pair (only once) */
437 			if (i == 0)
438 				ni_create_name_kstat("asu", ksinfop,
439 				    zam_asu_perf_events);
440 
441 			/* create counter kstats */
442 			zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
443 			    "asu", i, zam_cntr_kstat_update, ksinfop);
444 		}
445 	}
446 #endif
447 
448 #if defined(NIAGARA_IMPL)
449 	/*
450 	 * Create JBUS perf events kstat
451 	 */
452 	ni_jbus_kstat = (ni_ksinfo_t *)kmem_alloc(sizeof (ni_ksinfo_t),
453 	    KM_NOSLEEP);
454 
455 	if (ni_jbus_kstat == NULL) {
456 		cmn_err(CE_WARN, "%s: no space for niagara jbus kstat\n",
457 		    cpu_module_name);
458 	} else {
459 		ni_jbus_kstat->pic_no_evs =
460 		    sizeof (niagara_jbus_events) / sizeof (ni_kev_mask_t);
461 		ni_jbus_kstat->pic_sel_shift[0] = NIAGARA_JBUS_PIC0_SEL_SHIFT;
462 		ni_jbus_kstat->pic_shift[0] = NIAGARA_JBUS_PIC0_SHIFT;
463 		ni_jbus_kstat->pic_mask[0] = NIAGARA_JBUS_PIC0_MASK;
464 		ni_jbus_kstat->pic_sel_shift[1] = NIAGARA_JBUS_PIC1_SEL_SHIFT;
465 		ni_jbus_kstat->pic_shift[1] = NIAGARA_JBUS_PIC1_SHIFT;
466 		ni_jbus_kstat->pic_mask[1] = NIAGARA_JBUS_PIC1_MASK;
467 		ni_jbus_kstat->pic_reg[0] = HV_NIAGARA_JBUS_COUNT;
468 		ni_jbus_kstat->pcr_reg = HV_NIAGARA_JBUS_CTL;
469 		ni_create_name_kstat("jbus", ni_jbus_kstat,
470 		    niagara_jbus_events);
471 		ni_jbus_kstat->cntr_ksp = ni_create_cntr_kstat("jbus", 0,
472 		    ni_cntr_kstat_update, ni_jbus_kstat);
473 	}
474 #endif
475 }
476 
477 void
478 niagara_kstat_fini()
479 {
480 	int i;
481 
482 #ifdef DEBUG
483 	if (ni_perf_debug)
484 		printf("ni_kstat_fini called\n");
485 #endif
486 
487 	for (i = 0; i < NIAGARA_DRAM_BANKS; i++) {
488 		if (ni_dram_kstats[i] != NULL) {
489 			ni_delete_name_kstat(ni_dram_kstats[i]);
490 			if (ni_dram_kstats[i]->cntr_ksp != NULL)
491 				kstat_delete(ni_dram_kstats[i]->cntr_ksp);
492 			kmem_free(ni_dram_kstats[i], sizeof (ni_ksinfo_t));
493 			ni_dram_kstats[i] = NULL;
494 		}
495 	}
496 
497 #if defined(VFALLS_IMPL)
498 	for (i = 0; i < ZAMBEZI_LPU_COUNTERS; i++) {
499 		if (zam_lpu_kstats[i] != NULL) {
500 			ni_delete_name_kstat(zam_lpu_kstats[i]);
501 			if (zam_lpu_kstats[i]->cntr_ksp != NULL)
502 				kstat_delete(zam_lpu_kstats[i]->cntr_ksp);
503 			kmem_free(zam_lpu_kstats[i], sizeof (ni_ksinfo_t));
504 			zam_lpu_kstats[i] = NULL;
505 		}
506 	}
507 
508 	for (i = 0; i < ZAMBEZI_GPD_COUNTERS; i++) {
509 		if (zam_gpd_kstats[i] != NULL) {
510 			ni_delete_name_kstat(zam_gpd_kstats[i]);
511 			if (zam_gpd_kstats[i]->cntr_ksp != NULL)
512 				kstat_delete(zam_gpd_kstats[i]->cntr_ksp);
513 			kmem_free(zam_gpd_kstats[i], sizeof (ni_ksinfo_t));
514 			zam_gpd_kstats[i] = NULL;
515 		}
516 	}
517 
518 	for (i = 0; i < ZAMBEZI_ASU_COUNTERS; i++) {
519 		if (zam_asu_kstats[i] != NULL) {
520 			ni_delete_name_kstat(zam_asu_kstats[i]);
521 			if (zam_asu_kstats[i]->cntr_ksp != NULL)
522 				kstat_delete(zam_asu_kstats[i]->cntr_ksp);
523 			kmem_free(zam_asu_kstats[i], sizeof (ni_ksinfo_t));
524 			zam_asu_kstats[i] = NULL;
525 		}
526 	}
527 #endif
528 
529 #if defined(NIAGARA_IMPL)
530 	if (ni_jbus_kstat != NULL) {
531 		ni_delete_name_kstat(ni_jbus_kstat);
532 		if (ni_jbus_kstat->cntr_ksp != NULL)
533 			kstat_delete(ni_jbus_kstat->cntr_ksp);
534 		kmem_free(ni_jbus_kstat, sizeof (ni_ksinfo_t));
535 		ni_jbus_kstat = NULL;
536 	}
537 #endif
538 }
539 
540 static void
541 ni_create_name_kstat(char *name, ni_ksinfo_t *pp, ni_kev_mask_t *ev)
542 {
543 	int	i;
544 
545 #ifdef DEBUG
546 	if (ni_perf_debug > 1)
547 		printf("ni_create_name_kstat: name: %s\n", name);
548 #endif
549 	for (i = 0; i < NUM_OF_PICS; i++) {
550 		pp->pic_name_ksp[i] = ni_create_picN_kstat(name,
551 		    i, pp->pic_sel_shift[i], pp->pic_no_evs, ev);
552 
553 		if (pp->pic_name_ksp[i] == NULL) {
554 			cmn_err(CE_WARN, "%s: unable to create name kstat",
555 			    cpu_module_name);
556 		}
557 	}
558 }
559 
560 static void
561 ni_delete_name_kstat(ni_ksinfo_t *pp)
562 {
563 	int	i;
564 
565 	if (pp != NULL) {
566 		for (i = 0; i < NUM_OF_PICS; i++) {
567 			if (pp->pic_name_ksp[i] != NULL)
568 				kstat_delete(pp->pic_name_ksp[i]);
569 		}
570 	}
571 }
572 
573 /*
574  * Create the picN kstat. Returns a pointer to the
575  * kstat which the driver must store to allow it
576  * to be deleted when necessary.
577  */
578 static kstat_t *
579 ni_create_picN_kstat(char *mod_name, int pic, int pic_sel_shift,
580 	int num_ev, ni_kev_mask_t *ev_array)
581 {
582 	struct kstat_named *pic_named_data;
583 	int	inst = 0;
584 	int	event;
585 	char	pic_name[30];
586 	kstat_t	*picN_ksp = NULL;
587 
588 	(void) sprintf(pic_name, "pic%d", pic);
589 	if ((picN_ksp = kstat_create(mod_name, inst, pic_name,
590 	    "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) {
591 		cmn_err(CE_WARN, "%s %s : kstat create failed",
592 		    mod_name, pic_name);
593 
594 		/*
595 		 * It is up to the calling function to delete any kstats
596 		 * that may have been created already. We just
597 		 * return NULL to indicate an error has occured.
598 		 */
599 		return (NULL);
600 	}
601 
602 	pic_named_data = (struct kstat_named *)
603 	    picN_ksp->ks_data;
604 
605 	/*
606 	 * Write event names and their associated pcr masks. The
607 	 * last entry in the array (clear_pic) is added seperately
608 	 * below as the pic value must be inverted.
609 	 */
610 	for (event = 0; event < num_ev - 1; event++) {
611 		pic_named_data[event].value.ui64 =
612 		    (ev_array[event].pcr_mask << pic_sel_shift);
613 
614 		kstat_named_init(&pic_named_data[event],
615 		    ev_array[event].event_name,
616 		    KSTAT_DATA_UINT64);
617 	}
618 
619 	/*
620 	 * add the clear_pic entry.
621 	 */
622 	pic_named_data[event].value.ui64 =
623 	    (uint64_t)~(ev_array[event].pcr_mask << pic_sel_shift);
624 
625 	kstat_named_init(&pic_named_data[event], ev_array[event].event_name,
626 	    KSTAT_DATA_UINT64);
627 
628 	kstat_install(picN_ksp);
629 
630 	return (picN_ksp);
631 }
632 
633 /*
634  * Create the "counters" kstat.
635  */
636 static kstat_t *
637 ni_create_cntr_kstat(char *name, int instance, int (*update)(kstat_t *, int),
638 	void *ksinfop)
639 {
640 	struct kstat	*counters_ksp;
641 	struct kstat_named	*counters_named_data;
642 	char		pic_str[10];
643 	int		i;
644 	int		num_pics = NUM_OF_PICS;
645 
646 #ifdef DEBUG
647 	if (ni_perf_debug > 1)
648 		printf("ni_create_cntr_kstat: name: %s instance: %d\n",
649 		    name, instance);
650 #endif
651 
652 	/*
653 	 * Size of kstat is num_pics + 1 as it
654 	 * also contains the %pcr
655 	 */
656 	if ((counters_ksp = kstat_create(name, instance, "counters", "bus",
657 	    KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) {
658 		cmn_err(CE_WARN,
659 		    "%s: kstat_create for %s%d failed", cpu_module_name,
660 		    name, instance);
661 		return (NULL);
662 	}
663 
664 	counters_named_data = (struct kstat_named *)(counters_ksp->ks_data);
665 
666 	/*
667 	 * Iinitialize the named kstats
668 	 */
669 	kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64);
670 
671 	for (i = 0; i < num_pics; i++) {
672 		(void) sprintf(pic_str, "pic%d", i);
673 
674 		kstat_named_init(&counters_named_data[i+1], pic_str,
675 		    KSTAT_DATA_UINT64);
676 	}
677 
678 	/*
679 	 * Store the register offset's in the kstat's
680 	 * private field so that they are available
681 	 * to the update function.
682 	 */
683 	counters_ksp->ks_private = (void *)ksinfop;
684 	counters_ksp->ks_update = update;
685 
686 	kstat_install(counters_ksp);
687 
688 	return (counters_ksp);
689 }
690 
691 #if defined(VFALLS_IMPL)
692 /*
693  * zambezi kstat update function. Handles reads/writes
694  * from/to kstat.
695  */
696 static int
697 zam_cntr_kstat_update(kstat_t *ksp, int rw)
698 {
699 	struct kstat_named	*data_p;
700 	ni_ksinfo_t	*ksinfop = ksp->ks_private;
701 	uint64_t	pic0, pic1, pcr;
702 	int		stat = 0;
703 	uint64_t	pic0_stat = 0, pic1_stat = 0, pcr_stat = 0;
704 
705 	data_p = (struct kstat_named *)ksp->ks_data;
706 
707 	if (rw == KSTAT_WRITE) {
708 #ifdef DEBUG
709 		if (ni_perf_debug)
710 			printf("zam_cntr_kstat_update: wr pcr-%d: %lx\n",
711 			    ksinfop->pcr_reg, data_p[0].value.ui64);
712 #endif
713 		if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64))
714 			stat = EACCES;
715 	} else {
716 		do {
717 			pic0_stat = hv_niagara_getperf(ksinfop->pic_reg[0],
718 			    &pic0);
719 		} while (pic0_stat == H_EWOULDBLOCK);
720 		do {
721 			pic1_stat = hv_niagara_getperf(ksinfop->pic_reg[1],
722 			    &pic1);
723 		} while (pic1_stat == H_EWOULDBLOCK);
724 		do {
725 			pcr_stat = hv_niagara_getperf(ksinfop->pcr_reg,
726 			    &pcr);
727 		} while (pcr_stat == H_EWOULDBLOCK);
728 		if (pic0_stat != 0 || pic1_stat != 0 || pcr_stat != 0)
729 			stat = EACCES;
730 		else {
731 			data_p[0].value.ui64 = pcr;
732 			data_p[1].value.ui64 = pic0;
733 			data_p[2].value.ui64 = pic1;
734 		}
735 #ifdef DEBUG
736 		if (ni_perf_debug)
737 			printf("zam_cntr_kstat_update: rd pcr%d: %lx  "
738 			    "pic0: %16lx pic1: %16lx\n",
739 			    ksinfop->pcr_reg, pcr,
740 			    data_p[1].value.ui64, data_p[2].value.ui64);
741 #endif
742 	}
743 
744 	return (stat);
745 }
746 #endif
747 
748 /*
749  * kstat update function. Handles reads/writes
750  * from/to kstat.
751  */
752 static int
753 ni_cntr_kstat_update(kstat_t *ksp, int rw)
754 {
755 	struct kstat_named	*data_p;
756 	ni_ksinfo_t	*ksinfop = ksp->ks_private;
757 	uint64_t	pic, pcr;
758 	int		stat = 0;
759 	uint32_t	pic0, pic1;
760 
761 	data_p = (struct kstat_named *)ksp->ks_data;
762 
763 	if (rw == KSTAT_WRITE) {
764 #ifdef DEBUG
765 		if (ni_perf_debug)
766 			printf("ni_cntr_kstat_update: wr pcr-%d: %lx\n",
767 			    ksinfop->pcr_reg, data_p[0].value.ui64);
768 #endif
769 		if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64))
770 			stat = EACCES;
771 	} else {
772 		if (hv_niagara_getperf(ksinfop->pic_reg[0], &pic) != 0 ||
773 		    hv_niagara_getperf(ksinfop->pcr_reg, &pcr) != 0)
774 			stat = EACCES;
775 		else {
776 
777 			data_p[0].value.ui64 = pcr;
778 
779 			/*
780 			 * Generate a 32-bit PIC0 value by detecting overflow
781 			 */
782 			pic0 = (uint32_t)((pic >> ksinfop->pic_shift[0]) &
783 			    ksinfop->pic_mask[0]);
784 			if (pic0 < ksinfop->pic_last_val[0])
785 				ksinfop->pic_overflow[0]++;
786 			ksinfop->pic_last_val[0] = pic0;
787 			pic0 += (ksinfop->pic_overflow[0] & 1) << 31;
788 			data_p[1].value.ui64 = (uint64_t)pic0;
789 
790 			/*
791 			 * Generate a 32-bit PIC1 value by detecting overflow
792 			 */
793 			pic1 = (uint32_t)((pic >> ksinfop->pic_shift[1]) &
794 			    ksinfop->pic_mask[1]);
795 			if (pic1 < ksinfop->pic_last_val[1])
796 				ksinfop->pic_overflow[1]++;
797 			ksinfop->pic_last_val[1] = pic1;
798 			pic1 += (ksinfop->pic_overflow[1] & 1) << 31;
799 			data_p[2].value.ui64 = (uint64_t)pic1;
800 		}
801 #ifdef DEBUG
802 		if (ni_perf_debug)
803 			printf("ni_cntr_kstat_update: rd pcr%d: %lx  "
804 			    "pic%d: %16lx pic0: %8lx pic1: %8lx\n",
805 			    ksinfop->pcr_reg, pcr, ksinfop->pic_reg[0], pic,
806 			    data_p[1].value.ui64, data_p[2].value.ui64);
807 #endif
808 	}
809 	return (stat);
810 }
811