xref: /illumos-gate/usr/src/uts/sun4v/cpu/niagara_perfctr.c (revision 64cfc8ed0c5da83f827c424588bfe709e3fb5a7a)
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 	uint64_t pcr;
285 	uint64_t stat;
286 
287 #ifdef DEBUG
288 	if (ni_perf_debug)
289 		printf("ni_kstat_init called\n");
290 #endif
291 
292 	/*
293 	 * Create DRAM perf events kstat
294 	 */
295 	for (i = 0; i < NIAGARA_DRAM_BANKS; i++) {
296 #ifdef VFALLS_IMPL
297 		/* check if this dram instance is enabled in the HW */
298 		stat = hv_niagara_getperf(dram_perf_regs[i].pcr_reg, &pcr);
299 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
300 #endif
301 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
302 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
303 
304 			if (ksinfop == NULL) {
305 				cmn_err(CE_WARN,
306 				    "%s: no space for dram kstat\n",
307 				    cpu_module_name);
308 				break;
309 			}
310 			ksinfop->pic_no_evs =
311 			    sizeof (niagara_dram_events) /
312 			    sizeof (ni_kev_mask_t);
313 			ksinfop->pic_sel_shift[0] = NIAGARA_DRAM_PIC0_SEL_SHIFT;
314 			ksinfop->pic_shift[0] = NIAGARA_DRAM_PIC0_SHIFT;
315 			ksinfop->pic_mask[0] = NIAGARA_DRAM_PIC0_MASK;
316 			ksinfop->pic_sel_shift[1] = NIAGARA_DRAM_PIC1_SEL_SHIFT;
317 			ksinfop->pic_shift[1] = NIAGARA_DRAM_PIC1_SHIFT;
318 			ksinfop->pic_mask[1] = NIAGARA_DRAM_PIC1_MASK;
319 			ksinfop->pic_reg[0] = dram_perf_regs[i].pic_reg;
320 			ksinfop->pcr_reg = dram_perf_regs[i].pcr_reg;
321 			ni_dram_kstats[i] = ksinfop;
322 
323 			/* create basic pic event/mask pair (only once) */
324 			if (i == 0)
325 				ni_create_name_kstat("dram", ksinfop,
326 				    niagara_dram_events);
327 
328 			/* create counter kstats */
329 			ni_dram_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
330 			    "dram", i, ni_cntr_kstat_update, ksinfop);
331 #ifdef VFALLS_IMPL
332 		}
333 #endif
334 	}
335 
336 #ifdef VFALLS_IMPL
337 	/*
338 	 * Create Zambezi LPU perf events kstat
339 	 */
340 	for (i = 0; i < ZAMBEZI_LPU_COUNTERS; i++) {
341 		/* check if this Zambezi LPU instance is enabled in the HW */
342 		stat = hv_niagara_getperf(lpu_perf_regs[i].pcr_reg, &pcr);
343 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
344 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
345 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
346 
347 			if (ksinfop == NULL) {
348 				cmn_err(CE_WARN,
349 				    "%s: no space for zambezi lpu kstat\n",
350 				    cpu_module_name);
351 				break;
352 			}
353 			ksinfop->pic_no_evs =
354 			    sizeof (zam_lpu_perf_events) /
355 			    sizeof (ni_kev_mask_t);
356 			ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
357 			ksinfop->pic_reg[0] = lpu_perf_regs[i].pic_reg[0];
358 			ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
359 			ksinfop->pic_reg[1] = lpu_perf_regs[i].pic_reg[1];
360 			ksinfop->pcr_reg = lpu_perf_regs[i].pcr_reg;
361 			zam_lpu_kstats[i] = ksinfop;
362 
363 			/* create basic pic event/mask pair (only once) */
364 			if (i == 0)
365 				ni_create_name_kstat("lpu", ksinfop,
366 				    zam_lpu_perf_events);
367 
368 			/* create counter kstats */
369 			zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
370 			    "lpu", i, zam_cntr_kstat_update, ksinfop);
371 		}
372 	}
373 	/*
374 	 * Create Zambezi GPD perf events kstat
375 	 */
376 	for (i = 0; i < ZAMBEZI_GPD_COUNTERS; i++) {
377 		/* check if this Zambezi GPD instance is enabled in the HW */
378 		stat = hv_niagara_getperf(gpd_perf_regs[i].pcr_reg, &pcr);
379 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
380 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
381 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
382 
383 			if (ksinfop == NULL) {
384 				cmn_err(CE_WARN,
385 				    "%s: no space for zambezi gpd kstat\n",
386 				    cpu_module_name);
387 				break;
388 			}
389 			ksinfop->pic_no_evs =
390 			    sizeof (zam_gpd_perf_events) /
391 			    sizeof (ni_kev_mask_t);
392 			ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
393 			ksinfop->pic_reg[0] = gpd_perf_regs[i].pic_reg[0];
394 			ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
395 			ksinfop->pic_reg[1] = gpd_perf_regs[i].pic_reg[1];
396 			ksinfop->pcr_reg = gpd_perf_regs[i].pcr_reg;
397 			zam_gpd_kstats[i] = ksinfop;
398 
399 			/* create basic pic event/mask pair (only once) */
400 			if (i == 0)
401 				ni_create_name_kstat("gpd", ksinfop,
402 				    zam_gpd_perf_events);
403 
404 			/* create counter kstats */
405 			zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
406 			    "gpd", i, zam_cntr_kstat_update, ksinfop);
407 		}
408 	}
409 	/*
410 	 * Create Zambezi ASU perf events kstat
411 	 */
412 	for (i = 0; i < ZAMBEZI_ASU_COUNTERS; i++) {
413 		/* check if this Zambezi ASU instance is enabled in the HW */
414 		stat = hv_niagara_getperf(asu_perf_regs[i].pcr_reg, &pcr);
415 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
416 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
417 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
418 
419 			if (ksinfop == NULL) {
420 				cmn_err(CE_WARN,
421 				    "%s: no space for zambezi asu kstat\n",
422 				    cpu_module_name);
423 				break;
424 			}
425 			ksinfop->pic_no_evs =
426 			    sizeof (zam_asu_perf_events) /
427 			    sizeof (ni_kev_mask_t);
428 			ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
429 			ksinfop->pic_reg[0] = asu_perf_regs[i].pic_reg[0];
430 			ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
431 			ksinfop->pic_reg[1] = asu_perf_regs[i].pic_reg[1];
432 			ksinfop->pcr_reg = asu_perf_regs[i].pcr_reg;
433 			zam_asu_kstats[i] = ksinfop;
434 
435 			/* create basic pic event/mask pair (only once) */
436 			if (i == 0)
437 				ni_create_name_kstat("asu", ksinfop,
438 				    zam_asu_perf_events);
439 
440 			/* create counter kstats */
441 			zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
442 			    "asu", i, zam_cntr_kstat_update, ksinfop);
443 		}
444 	}
445 #endif
446 
447 #if defined(NIAGARA_IMPL)
448 	/*
449 	 * Create JBUS perf events kstat
450 	 */
451 	ni_jbus_kstat = (ni_ksinfo_t *)kmem_alloc(sizeof (ni_ksinfo_t),
452 	    KM_NOSLEEP);
453 
454 	if (ni_jbus_kstat == NULL) {
455 		cmn_err(CE_WARN, "%s: no space for niagara jbus kstat\n",
456 		    cpu_module_name);
457 	} else {
458 		ni_jbus_kstat->pic_no_evs =
459 		    sizeof (niagara_jbus_events) / sizeof (ni_kev_mask_t);
460 		ni_jbus_kstat->pic_sel_shift[0] = NIAGARA_JBUS_PIC0_SEL_SHIFT;
461 		ni_jbus_kstat->pic_shift[0] = NIAGARA_JBUS_PIC0_SHIFT;
462 		ni_jbus_kstat->pic_mask[0] = NIAGARA_JBUS_PIC0_MASK;
463 		ni_jbus_kstat->pic_sel_shift[1] = NIAGARA_JBUS_PIC1_SEL_SHIFT;
464 		ni_jbus_kstat->pic_shift[1] = NIAGARA_JBUS_PIC1_SHIFT;
465 		ni_jbus_kstat->pic_mask[1] = NIAGARA_JBUS_PIC1_MASK;
466 		ni_jbus_kstat->pic_reg[0] = HV_NIAGARA_JBUS_COUNT;
467 		ni_jbus_kstat->pcr_reg = HV_NIAGARA_JBUS_CTL;
468 		ni_create_name_kstat("jbus", ni_jbus_kstat,
469 		    niagara_jbus_events);
470 		ni_jbus_kstat->cntr_ksp = ni_create_cntr_kstat("jbus", 0,
471 		    ni_cntr_kstat_update, ni_jbus_kstat);
472 	}
473 #endif
474 }
475 
476 void
477 niagara_kstat_fini()
478 {
479 	int i;
480 
481 #ifdef DEBUG
482 	if (ni_perf_debug)
483 		printf("ni_kstat_fini called\n");
484 #endif
485 
486 	for (i = 0; i < NIAGARA_DRAM_BANKS; i++) {
487 		if (ni_dram_kstats[i] != NULL) {
488 			ni_delete_name_kstat(ni_dram_kstats[i]);
489 			if (ni_dram_kstats[i]->cntr_ksp != NULL)
490 				kstat_delete(ni_dram_kstats[i]->cntr_ksp);
491 			kmem_free(ni_dram_kstats[i], sizeof (ni_ksinfo_t));
492 			ni_dram_kstats[i] = NULL;
493 		}
494 	}
495 
496 #if defined(VFALLS_IMPL)
497 	for (i = 0; i < ZAMBEZI_LPU_COUNTERS; i++) {
498 		if (zam_lpu_kstats[i] != NULL) {
499 			ni_delete_name_kstat(zam_lpu_kstats[i]);
500 			if (zam_lpu_kstats[i]->cntr_ksp != NULL)
501 				kstat_delete(zam_lpu_kstats[i]->cntr_ksp);
502 			kmem_free(zam_lpu_kstats[i], sizeof (ni_ksinfo_t));
503 			zam_lpu_kstats[i] = NULL;
504 		}
505 	}
506 
507 	for (i = 0; i < ZAMBEZI_GPD_COUNTERS; i++) {
508 		if (zam_gpd_kstats[i] != NULL) {
509 			ni_delete_name_kstat(zam_gpd_kstats[i]);
510 			if (zam_gpd_kstats[i]->cntr_ksp != NULL)
511 				kstat_delete(zam_gpd_kstats[i]->cntr_ksp);
512 			kmem_free(zam_gpd_kstats[i], sizeof (ni_ksinfo_t));
513 			zam_gpd_kstats[i] = NULL;
514 		}
515 	}
516 
517 	for (i = 0; i < ZAMBEZI_ASU_COUNTERS; i++) {
518 		if (zam_asu_kstats[i] != NULL) {
519 			ni_delete_name_kstat(zam_asu_kstats[i]);
520 			if (zam_asu_kstats[i]->cntr_ksp != NULL)
521 				kstat_delete(zam_asu_kstats[i]->cntr_ksp);
522 			kmem_free(zam_asu_kstats[i], sizeof (ni_ksinfo_t));
523 			zam_asu_kstats[i] = NULL;
524 		}
525 	}
526 #endif
527 
528 #if defined(NIAGARA_IMPL)
529 	if (ni_jbus_kstat != NULL) {
530 		ni_delete_name_kstat(ni_jbus_kstat);
531 		if (ni_jbus_kstat->cntr_ksp != NULL)
532 			kstat_delete(ni_jbus_kstat->cntr_ksp);
533 		kmem_free(ni_jbus_kstat, sizeof (ni_ksinfo_t));
534 		ni_jbus_kstat = NULL;
535 	}
536 #endif
537 }
538 
539 static void
540 ni_create_name_kstat(char *name, ni_ksinfo_t *pp, ni_kev_mask_t *ev)
541 {
542 	int	i;
543 
544 #ifdef DEBUG
545 	if (ni_perf_debug > 1)
546 		printf("ni_create_name_kstat: name: %s\n", name);
547 #endif
548 	for (i = 0; i < NUM_OF_PICS; i++) {
549 		pp->pic_name_ksp[i] = ni_create_picN_kstat(name,
550 		    i, pp->pic_sel_shift[i], pp->pic_no_evs, ev);
551 
552 		if (pp->pic_name_ksp[i] == NULL) {
553 			cmn_err(CE_WARN, "%s: unable to create name kstat",
554 			    cpu_module_name);
555 		}
556 	}
557 }
558 
559 static void
560 ni_delete_name_kstat(ni_ksinfo_t *pp)
561 {
562 	int	i;
563 
564 	if (pp != NULL) {
565 		for (i = 0; i < NUM_OF_PICS; i++) {
566 			if (pp->pic_name_ksp[i] != NULL)
567 				kstat_delete(pp->pic_name_ksp[i]);
568 		}
569 	}
570 }
571 
572 /*
573  * Create the picN kstat. Returns a pointer to the
574  * kstat which the driver must store to allow it
575  * to be deleted when necessary.
576  */
577 static kstat_t *
578 ni_create_picN_kstat(char *mod_name, int pic, int pic_sel_shift,
579 	int num_ev, ni_kev_mask_t *ev_array)
580 {
581 	struct kstat_named *pic_named_data;
582 	int	inst = 0;
583 	int	event;
584 	char	pic_name[30];
585 	kstat_t	*picN_ksp = NULL;
586 
587 	(void) sprintf(pic_name, "pic%d", pic);
588 	if ((picN_ksp = kstat_create(mod_name, inst, pic_name,
589 	    "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) {
590 		cmn_err(CE_WARN, "%s %s : kstat create failed",
591 		    mod_name, pic_name);
592 
593 		/*
594 		 * It is up to the calling function to delete any kstats
595 		 * that may have been created already. We just
596 		 * return NULL to indicate an error has occured.
597 		 */
598 		return (NULL);
599 	}
600 
601 	pic_named_data = (struct kstat_named *)
602 	    picN_ksp->ks_data;
603 
604 	/*
605 	 * Write event names and their associated pcr masks. The
606 	 * last entry in the array (clear_pic) is added seperately
607 	 * below as the pic value must be inverted.
608 	 */
609 	for (event = 0; event < num_ev - 1; event++) {
610 		pic_named_data[event].value.ui64 =
611 		    (ev_array[event].pcr_mask << pic_sel_shift);
612 
613 		kstat_named_init(&pic_named_data[event],
614 		    ev_array[event].event_name,
615 		    KSTAT_DATA_UINT64);
616 	}
617 
618 	/*
619 	 * add the clear_pic entry.
620 	 */
621 	pic_named_data[event].value.ui64 =
622 	    (uint64_t)~(ev_array[event].pcr_mask << pic_sel_shift);
623 
624 	kstat_named_init(&pic_named_data[event], ev_array[event].event_name,
625 	    KSTAT_DATA_UINT64);
626 
627 	kstat_install(picN_ksp);
628 
629 	return (picN_ksp);
630 }
631 
632 /*
633  * Create the "counters" kstat.
634  */
635 static kstat_t *
636 ni_create_cntr_kstat(char *name, int instance, int (*update)(kstat_t *, int),
637 	void *ksinfop)
638 {
639 	struct kstat	*counters_ksp;
640 	struct kstat_named	*counters_named_data;
641 	char		pic_str[10];
642 	int		i;
643 	int		num_pics = NUM_OF_PICS;
644 
645 #ifdef DEBUG
646 	if (ni_perf_debug > 1)
647 		printf("ni_create_cntr_kstat: name: %s instance: %d\n",
648 		    name, instance);
649 #endif
650 
651 	/*
652 	 * Size of kstat is num_pics + 1 as it
653 	 * also contains the %pcr
654 	 */
655 	if ((counters_ksp = kstat_create(name, instance, "counters", "bus",
656 	    KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) {
657 		cmn_err(CE_WARN,
658 		    "%s: kstat_create for %s%d failed", cpu_module_name,
659 		    name, instance);
660 		return (NULL);
661 	}
662 
663 	counters_named_data = (struct kstat_named *)(counters_ksp->ks_data);
664 
665 	/*
666 	 * Iinitialize the named kstats
667 	 */
668 	kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64);
669 
670 	for (i = 0; i < num_pics; i++) {
671 		(void) sprintf(pic_str, "pic%d", i);
672 
673 		kstat_named_init(&counters_named_data[i+1], pic_str,
674 		    KSTAT_DATA_UINT64);
675 	}
676 
677 	/*
678 	 * Store the register offset's in the kstat's
679 	 * private field so that they are available
680 	 * to the update function.
681 	 */
682 	counters_ksp->ks_private = (void *)ksinfop;
683 	counters_ksp->ks_update = update;
684 
685 	kstat_install(counters_ksp);
686 
687 	return (counters_ksp);
688 }
689 
690 #if defined(VFALLS_IMPL)
691 /*
692  * zambezi kstat update function. Handles reads/writes
693  * from/to kstat.
694  */
695 static int
696 zam_cntr_kstat_update(kstat_t *ksp, int rw)
697 {
698 	struct kstat_named	*data_p;
699 	ni_ksinfo_t	*ksinfop = ksp->ks_private;
700 	uint64_t	pic0, pic1, pcr;
701 	int		stat = 0;
702 	uint64_t	pic0_stat = 0, pic1_stat = 0, pcr_stat = 0;
703 
704 	data_p = (struct kstat_named *)ksp->ks_data;
705 
706 	if (rw == KSTAT_WRITE) {
707 #ifdef DEBUG
708 		if (ni_perf_debug)
709 			printf("zam_cntr_kstat_update: wr pcr-%d: %lx\n",
710 			    ksinfop->pcr_reg, data_p[0].value.ui64);
711 #endif
712 		if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64))
713 			stat = EACCES;
714 	} else {
715 		do {
716 			pic0_stat = hv_niagara_getperf(ksinfop->pic_reg[0],
717 			    &pic0);
718 		} while (pic0_stat == H_EWOULDBLOCK);
719 		do {
720 			pic1_stat = hv_niagara_getperf(ksinfop->pic_reg[1],
721 			    &pic1);
722 		} while (pic1_stat == H_EWOULDBLOCK);
723 		do {
724 			pcr_stat = hv_niagara_getperf(ksinfop->pcr_reg,
725 			    &pcr);
726 		} while (pcr_stat == H_EWOULDBLOCK);
727 		if (pic0_stat != 0 || pic1_stat != 0 || pcr_stat != 0)
728 			stat = EACCES;
729 		else {
730 			data_p[0].value.ui64 = pcr;
731 			data_p[1].value.ui64 = pic0;
732 			data_p[2].value.ui64 = pic1;
733 		}
734 #ifdef DEBUG
735 		if (ni_perf_debug)
736 			printf("zam_cntr_kstat_update: rd pcr%d: %lx  "
737 			    "pic0: %16lx pic1: %16lx\n",
738 			    ksinfop->pcr_reg, pcr,
739 			    data_p[1].value.ui64, data_p[2].value.ui64);
740 #endif
741 	}
742 
743 	return (stat);
744 }
745 #endif
746 
747 /*
748  * kstat update function. Handles reads/writes
749  * from/to kstat.
750  */
751 static int
752 ni_cntr_kstat_update(kstat_t *ksp, int rw)
753 {
754 	struct kstat_named	*data_p;
755 	ni_ksinfo_t	*ksinfop = ksp->ks_private;
756 	uint64_t	pic, pcr;
757 	int		stat = 0;
758 	uint32_t	pic0, pic1;
759 
760 	data_p = (struct kstat_named *)ksp->ks_data;
761 
762 	if (rw == KSTAT_WRITE) {
763 #ifdef DEBUG
764 		if (ni_perf_debug)
765 			printf("ni_cntr_kstat_update: wr pcr-%d: %lx\n",
766 			    ksinfop->pcr_reg, data_p[0].value.ui64);
767 #endif
768 		if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64))
769 			stat = EACCES;
770 	} else {
771 		if (hv_niagara_getperf(ksinfop->pic_reg[0], &pic) != 0 ||
772 		    hv_niagara_getperf(ksinfop->pcr_reg, &pcr) != 0)
773 			stat = EACCES;
774 		else {
775 
776 			data_p[0].value.ui64 = pcr;
777 
778 			/*
779 			 * Generate a 32-bit PIC0 value by detecting overflow
780 			 */
781 			pic0 = (uint32_t)((pic >> ksinfop->pic_shift[0]) &
782 			    ksinfop->pic_mask[0]);
783 			if (pic0 < ksinfop->pic_last_val[0])
784 				ksinfop->pic_overflow[0]++;
785 			ksinfop->pic_last_val[0] = pic0;
786 			pic0 += (ksinfop->pic_overflow[0] & 1) << 31;
787 			data_p[1].value.ui64 = (uint64_t)pic0;
788 
789 			/*
790 			 * Generate a 32-bit PIC1 value by detecting overflow
791 			 */
792 			pic1 = (uint32_t)((pic >> ksinfop->pic_shift[1]) &
793 			    ksinfop->pic_mask[1]);
794 			if (pic1 < ksinfop->pic_last_val[1])
795 				ksinfop->pic_overflow[1]++;
796 			ksinfop->pic_last_val[1] = pic1;
797 			pic1 += (ksinfop->pic_overflow[1] & 1) << 31;
798 			data_p[2].value.ui64 = (uint64_t)pic1;
799 		}
800 #ifdef DEBUG
801 		if (ni_perf_debug)
802 			printf("ni_cntr_kstat_update: rd pcr%d: %lx  "
803 			    "pic%d: %16lx pic0: %8lx pic1: %8lx\n",
804 			    ksinfop->pcr_reg, pcr, ksinfop->pic_reg[0], pic,
805 			    data_p[1].value.ui64, data_p[2].value.ui64);
806 #endif
807 	}
808 	return (stat);
809 }
810