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