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
40extern char cpu_module_name[];
41
42/*
43 * Data structure used to build array of event-names and pcr-mask values
44 */
45typedef 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
63typedef 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
76static ni_ksinfo_t	*ni_dram_kstats[DRAM_BANKS];
77
78#if defined(NIAGARA_IMPL)
79static ni_ksinfo_t	*ni_jbus_kstat;
80#endif
81
82typedef struct ni_perf_regs {
83	uint32_t	pcr_reg;
84	uint32_t	pic_reg[NUM_OF_PIC_REGS];
85} ni_perf_regs_t;
86
87static 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 */
110static ni_ksinfo_t	*zam_lpu_kstats[ZAMBEZI_LPU_COUNTERS];
111static ni_ksinfo_t	*zam_gpd_kstats[ZAMBEZI_GPD_COUNTERS];
112static ni_ksinfo_t	*zam_asu_kstats[ZAMBEZI_ASU_COUNTERS];
113
114typedef struct zam_perf_regs {
115	uint32_t	pcr_reg;
116	uint32_t	pic_reg[NUM_OF_PICS];
117} zam_perf_regs_t;
118
119static 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
141static 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
148static 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
155static int zam_cntr_kstat_update(kstat_t *, int);
156#endif
157
158static void ni_create_name_kstat(char *, ni_ksinfo_t *, ni_kev_mask_t *);
159static void ni_delete_name_kstat(ni_ksinfo_t *);
160
161static kstat_t *ni_create_cntr_kstat(char *, int,
162	int (*update)(kstat_t *, int), void *);
163
164static int ni_cntr_kstat_update(kstat_t *, int);
165
166static kstat_t *ni_create_picN_kstat(char *, int, int, int,
167	ni_kev_mask_t *);
168
169#ifdef DEBUG
170static int	ni_perf_debug;
171#endif
172
173/*
174 * Niagara, Niagara2 and VFalls DRAM Performance Events
175 */
176static ni_kev_mask_t
177niagara_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 */
210static ni_kev_mask_t
211zam_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
257static ni_kev_mask_t
258zam_gpd_perf_events[] = {
259	{"none",		0x0},
260	{"clock_cycles",	0x1},
261	{"clear_pic",		0xf}
262};
263
264static ni_kev_mask_t
265zam_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 */
280static ni_kev_mask_t
281niagara_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 */
300void
301niagara_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
498void
499niagara_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
561static void
562ni_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
581static void
582ni_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 */
599static kstat_t *
600ni_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 */
657static kstat_t *
658ni_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 */
717static int
718zam_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 */
773static int
774ni_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