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