xref: /titanic_50/usr/src/uts/sun4v/io/n2piupc/n2piupc_kstats.c (revision b86efd96f8acd85ddaa930a2f0c1d664237e4aaf)
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 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/kstat.h>
31 #include "n2piupc_acc.h"
32 #include "n2piupc_tables.h"
33 #include "n2piupc.h"
34 #include "n2piupc_biterr.h"
35 
36 #define	PIC_STR_LEN	5	/* Size of a PICx name string. */
37 
38 static int n2piupc_create_name_kstat(n2piu_grp_t *grp);
39 static void n2piupc_delete_name_kstats(kstat_t **name_kstats_pp,
40     int num_kstats);
41 static kstat_t *n2piupc_create_cntr_kstat(char *name, int dev_inst,
42     int (*update)(kstat_t *, int), n2piu_ksinfo_t *ksinfop, int num_pics);
43 static int n2piupc_kstat_update(kstat_t *ksp, int rw);
44 static kstat_t *n2piupc_create_picN_kstat(char *mod_name, int pic,
45     uint64_t mask, int num_ev, n2piu_event_t *ev_array);
46 
47 /*
48  * One-time initialization for this module.
49  */
50 int
51 n2piupc_kstat_init()
52 {
53 	n2piu_grp_t **grp_pp;
54 	n2piu_grp_t *grp_p;
55 
56 	N2PIUPC_DBG2("n2piupc: kstat_init: enter\n");
57 
58 	/*
59 	 * Initialize the name kstats for each group, drawing upon the table
60 	 * for values.
61 	 */
62 	for (grp_pp = leaf_grps; *grp_pp != NULL; grp_pp++) {
63 
64 		grp_p = *grp_pp;
65 
66 		N2PIUPC_DBG2("Setting up group for %s\n", grp_p->grp_name);
67 
68 		/* Create basic pic event-type pair. */
69 		grp_p->name_kstats_pp = kmem_zalloc((grp_p->num_counters *
70 			sizeof (kstat_t)), KM_SLEEP);
71 		if (n2piupc_create_name_kstat(grp_p) != DDI_SUCCESS) {
72 			n2piupc_kstat_fini();
73 			N2PIUPC_DBG1("n2piupc: init: failure exit\n");
74 			return (DDI_FAILURE);
75 		}
76 	}
77 
78 	N2PIUPC_DBG2("n2piupc: kstat_init: success exit\n");
79 
80 	return (DDI_SUCCESS);
81 }
82 
83 /*
84  * Per-instance initialization for this module.
85  */
86 int
87 n2piupc_kstat_attach(n2piupc_t *n2piupc_p)
88 {
89 	n2piu_grp_t **grp_pp;
90 	n2piu_grp_t *grp_p;
91 	n2piu_ksinfo_t *ksinfo_p;
92 
93 	int i;
94 
95 	N2PIUPC_DBG2("n2piupc: kstat_attach %d: enter\n",
96 	    ddi_get_instance(n2piupc_p->n2piupc_dip));
97 
98 	/* Initialize biterr module.  Save opaque result. */
99 	if (n2piupc_biterr_attach(&n2piupc_p->n2piupc_biterr_p) != DDI_SUCCESS)
100 		goto err;
101 
102 	/* Set up kstats for each group. */
103 	for (i = 0, grp_pp = leaf_grps; *grp_pp != NULL; i++, grp_pp++) {
104 
105 		grp_p = *grp_pp;
106 
107 		/*
108 		 * ksinfo_p keeps all info needed by n2piupc_kstat_update,
109 		 * which is fired off asynchronously on demand by the kstat
110 		 * framework.
111 		 */
112 		ksinfo_p = (n2piu_ksinfo_t *)kmem_zalloc(
113 		    sizeof (n2piu_ksinfo_t), KM_SLEEP);
114 
115 		ksinfo_p->n2piupc_p = n2piupc_p;
116 		ksinfo_p->grp_p  = grp_p;
117 
118 		/* Also save in state structure, for later cleanup. */
119 		n2piupc_p->n2piupc_ksinfo_p[i] = ksinfo_p;
120 
121 		/* Create counter kstats */
122 		ksinfo_p->cntr_ksp = n2piupc_create_cntr_kstat(grp_p->grp_name,
123 		    ddi_get_instance(n2piupc_p->n2piupc_dip),
124 		    n2piupc_kstat_update, ksinfo_p, grp_p->num_counters);
125 		if (ksinfo_p->cntr_ksp == NULL)
126 			goto err;
127 	}
128 
129 	N2PIUPC_DBG2("n2piupc: kstat_attach: success exit\n");
130 	return (DDI_SUCCESS);
131 err:
132 	n2piupc_kstat_detach(n2piupc_p);
133 	N2PIUPC_DBG2("n2piupc: kstat_attach: failure exit\n");
134 	return (DDI_FAILURE);
135 }
136 
137 /*
138  * Create the name kstats for each group.
139  */
140 static int
141 n2piupc_create_name_kstat(n2piu_grp_t *grp_p)
142 {
143 	int i;
144 
145 	for (i = 0; i < grp_p->num_counters; i++) {
146 		grp_p->name_kstats_pp[i] = n2piupc_create_picN_kstat(
147 		    grp_p->grp_name, i,
148 		    grp_p->regsel_p->fields_p[i].event_offset,
149 		    grp_p->regsel_p->fields_p[i].num_events,
150 		    grp_p->regsel_p->fields_p[i].events_p);
151 
152 		if (grp_p->name_kstats_pp[i] == NULL)
153 			return (DDI_FAILURE);
154 	}
155 	return (DDI_SUCCESS);
156 }
157 
158 /*
159  * Create the picN kstat. Returns a pointer to the
160  * kstat which the driver must store to allow it
161  * to be deleted when necessary.
162  */
163 static kstat_t *
164 n2piupc_create_picN_kstat(char *mod_name, int pic, uint64_t ev_offset,
165     int num_ev, n2piu_event_t *ev_array)
166 {
167 	int event;
168 	char pic_name[PIC_STR_LEN];
169 	kstat_t	*picN_ksp = NULL;
170 	struct kstat_named *pic_named_data;
171 
172 
173 	(void) snprintf(pic_name, PIC_STR_LEN, "pic%1d", pic);
174 
175 	if ((picN_ksp = kstat_create(mod_name, 0, pic_name,
176 	    "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) {
177 		cmn_err(CE_WARN, "%s %s : kstat create failed",
178 		    mod_name, pic_name);
179 		return (NULL);
180 	}
181 
182 	/* NOTE: Number of events is assumed to always be non-zero. */
183 
184 	pic_named_data = (struct kstat_named *)picN_ksp->ks_data;
185 
186 	/*
187 	 * Fill up data section of the kstat
188 	 * Write event names and their associated pcr masks.
189 	 * num_ev - 1 is because CLEAR_PIC is added separately.
190 	 */
191 	for (event = 0; event < num_ev - 1; event++) {
192 		pic_named_data[event].value.ui64 =
193 		    ev_array[event].value << ev_offset;
194 
195 		kstat_named_init(&pic_named_data[event],
196 		    ev_array[event].name, KSTAT_DATA_UINT64);
197 	}
198 
199 	/*
200 	 * add the clear_pic entry
201 	 */
202 	pic_named_data[event].value.ui64 =
203 	    (uint64_t)~(ev_array[event].value << ev_offset);
204 
205 	kstat_named_init(&pic_named_data[event], ev_array[event].name,
206 	    KSTAT_DATA_UINT64);
207 
208 	kstat_install(picN_ksp);
209 
210 	return (picN_ksp);
211 }
212 
213 /*
214  * Create the "counters" kstat.
215  */
216 static kstat_t *
217 n2piupc_create_cntr_kstat(char *name, int dev_inst,
218     int (*update)(kstat_t *, int), n2piu_ksinfo_t *ksinfop, int num_pics)
219 {
220 	int i;
221 	char pic_str[PIC_STR_LEN];
222 	struct kstat *counters_ksp;
223 	struct kstat_named *counters_named_data;
224 
225 	N2PIUPC_DBG2("n2piupc_create_cntr_kstat: name: %s instance: %d\n",
226 	    name, dev_inst);
227 
228 	/*
229 	 * Size of kstat is num_pics + 1. extra one for pcr.
230 	 */
231 
232 	if ((counters_ksp = kstat_create(name, dev_inst, "counters", "bus",
233 	    KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) {
234 		cmn_err(CE_WARN, "%s%d: kstat_create for %s counters failed",
235 		    NAMEINST(ksinfop->n2piupc_p->n2piupc_dip), name);
236 		return (NULL);
237 	}
238 
239 	counters_named_data = (struct kstat_named *)(counters_ksp->ks_data);
240 	kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64);
241 
242 	for (i = 0; i < num_pics; i++) {
243 		(void) snprintf(pic_str, PIC_STR_LEN, "pic%1d", i);
244 
245 		kstat_named_init(&counters_named_data[i+1], pic_str,
246 		    KSTAT_DATA_UINT64);
247 	}
248 
249 	/*
250 	 * Store the reg type and other info. in the kstat's private field
251 	 * so that they are available to the update function.
252 	 */
253 	counters_ksp->ks_private = (void *)ksinfop;
254 	counters_ksp->ks_update = update;
255 
256 	kstat_install(counters_ksp);
257 
258 	return (counters_ksp);
259 }
260 
261 /* Higher-level register write, hides SW abstractions. */
262 static int
263 n2piupc_write(n2piupc_t *n2piupc_p, int regid, uint64_t data)
264 {
265 	int rval = SUCCESS;
266 
267 	switch (regid) {
268 	case SW_N2PIU_BITERR_SEL:
269 	case SW_N2PIU_BITERR_CLR:
270 		rval = n2piupc_biterr_write(n2piupc_p, regid, data);
271 		break;
272 
273 	default:
274 		if (n2piupc_set_perfreg(n2piupc_p->n2piupc_handle,
275 		    regid, data) != H_EOK)
276 			rval = EIO;
277 		break;
278 	}
279 
280 	N2PIUPC_DBG1("n2piupc_write: status:%d\n", rval);
281 	return (rval);
282 }
283 
284 
285 /* Higher-level register read, hides SW abstractions. */
286 static int
287 n2piupc_read(n2piupc_t *n2piupc_p, int regid, uint64_t *data)
288 {
289 	int rval = SUCCESS;
290 
291 	N2PIUPC_DBG2("n2piupc_read enter: regid:%d\n", regid);
292 
293 	/* This "register" is a layered SW-implemented reg. */
294 	switch (regid) {
295 	case SW_N2PIU_BITERR_CNT1_DATA:
296 	case SW_N2PIU_BITERR_CNT2_DATA:
297 	case SW_N2PIU_BITERR_SEL:
298 		rval = n2piupc_biterr_read(n2piupc_p, regid, data);
299 		break;
300 
301 	default:
302 		if (n2piupc_get_perfreg(n2piupc_p->n2piupc_handle,
303 		    regid, data) != H_EOK)
304 			rval = EIO;
305 		break;
306 	}
307 
308 	N2PIUPC_DBG1("n2piupc_read exit: data:0x%lx, status:%d\n", *data,
309 	    rval);
310 
311 	return (rval);
312 }
313 
314 
315 /*
316  * Program a performance counter.
317  *
318  * reggroup is which type of counter.
319  * counter is the counter number.
320  * event is the event to program for that counter.
321  */
322 static int
323 n2piupc_perfcnt_program(n2piupc_t *n2piupc_p, n2piu_grp_t *grp_p,
324     uint64_t new_events)
325 {
326 	uint64_t old_events;
327 	int rval = SUCCESS;
328 	uint64_t event_mask;
329 	int counter;
330 
331 	N2PIUPC_DBG1(
332 	    "n2piupc_perfcnt_program enter: new_events:0x%" PRIx64 "\n",
333 	    new_events);
334 
335 	if ((rval = n2piupc_read(n2piupc_p, grp_p->regsel_p->regoff,
336 	    &old_events)) != SUCCESS) {
337 		N2PIUPC_DBG1(
338 		    "Read of old event data failed, select reg offset:%ld\n",
339 		    grp_p->regsel_p->regoff);
340 		goto done_pgm;
341 	}
342 
343 	N2PIUPC_DBG1("  old_events:0x%" PRIx64 "\n", old_events);
344 
345 	for (counter = 0; counter < grp_p->num_counters; counter++) {
346 
347 		if (grp_p->counters_p[counter].zero_regoff == NO_REGISTER)
348 			continue;
349 
350 		event_mask = grp_p->regsel_p->fields_p[counter].event_mask <<
351 		    grp_p->regsel_p->fields_p[counter].event_offset;
352 
353 		N2PIUPC_DBG1(
354 		    "grp:%s, counter:%d, zero_regoff:0x%lx, "
355 		    "event_mask:0x%" PRIx64 ", old&mask:0x%lx, "
356 		    "new&mask:0x%lx\n",
357 		    grp_p->grp_name, counter,
358 		    grp_p->counters_p[counter].zero_regoff,
359 		    event_mask, old_events & event_mask,
360 		    new_events & event_mask);
361 
362 		if ((old_events & event_mask) ==
363 		    (new_events & event_mask))
364 			continue;
365 
366 		N2PIUPC_DBG1("Zeroing counter %d\n", counter);
367 		if ((rval = n2piupc_write(n2piupc_p,
368 		    grp_p->counters_p[counter].zero_regoff,
369 		    grp_p->counters_p[counter].zero_value)) != SUCCESS)
370 			goto done_pgm;
371 	}
372 
373 	if (old_events != new_events) {
374 		N2PIUPC_DBG1("old != new, setting event reg %ld to 0x%lx\n",
375 		    grp_p->regsel_p->regoff, new_events);
376 		if ((rval = n2piupc_write(n2piupc_p, grp_p->regsel_p->regoff,
377 		    new_events)) != SUCCESS) {
378 			N2PIUPC_DBG1(
379 			    "Write of new event data failed, "
380 			    "select reg offset: %ld\n",
381 			    grp_p->regsel_p->regoff);
382 			goto done_pgm;
383 		}
384 	}
385 done_pgm:
386 	N2PIUPC_DBG1("n2piupc_perfcnt_program: returning status %d.\n", rval);
387 	return (rval);
388 }
389 
390 /*
391  * kstat update function. Handles reads/writes
392  * from/to kstat.
393  */
394 static int
395 n2piupc_kstat_update(kstat_t *ksp, int rw)
396 {
397 	struct kstat_named *data_p;
398 	int counter;
399 	n2piu_ksinfo_t *ksinfop = ksp->ks_private;
400 	n2piu_grp_t *grp_p = ksinfop->grp_p;
401 	n2piupc_t *n2piupc_p = ksinfop->n2piupc_p;
402 
403 	data_p = (struct kstat_named *)ksp->ks_data;
404 
405 	if (rw == KSTAT_WRITE) {
406 
407 		N2PIUPC_DBG2("n2piupc_kstat_update: wr %ld\n",
408 		    data_p[0].value.ui64);
409 
410 		/*
411 		 * Fields without programmable events won't be zeroed as
412 		 * n2piupc_perfcnt_program is what zeros them.
413 		 */
414 
415 		/* This group has programmable events. */
416 		if (grp_p->regsel_p->regoff != NO_REGISTER) {
417 
418 			N2PIUPC_DBG2("write: regoff has valid register\n");
419 			if (n2piupc_perfcnt_program(n2piupc_p, grp_p,
420 			    data_p[0].value.ui64) != SUCCESS)
421 				return (EIO);
422 		}
423 
424 	} else {	/* Read the event register and all of the counters. */
425 
426 		/* This group has programmable events. */
427 		if (grp_p->regsel_p->regoff != NO_REGISTER) {
428 
429 			N2PIUPC_DBG2("read: regoff has valid register\n");
430 			if (n2piupc_read(n2piupc_p, grp_p->regsel_p->regoff,
431 			    &data_p[0].value.ui64) != SUCCESS)
432 				return (EIO);
433 		} else
434 			data_p[0].value.ui64 = 0ull;
435 
436 		N2PIUPC_DBG2("n2piupc_kstat_update: rd event %ld",
437 		    data_p[0].value.ui64);
438 
439 		for (counter = 0; counter < grp_p->num_counters; counter++) {
440 			if (n2piupc_read(n2piupc_p,
441 			    grp_p->counters_p[counter].regoff,
442 			    &data_p[counter + 1].value.ui64) != SUCCESS)
443 				return (EIO);
444 
445 			N2PIUPC_DBG2("cntr%d, off:0x%lx, val:0x%ld", counter,
446 			    grp_p->counters_p[counter].regoff,
447 			    data_p[counter + 1].value.ui64);
448 		}
449 	}
450 	return (SUCCESS);
451 }
452 
453 void
454 n2piupc_kstat_fini()
455 {
456 	n2piu_grp_t **grp_pp;
457 	n2piu_grp_t *grp_p;
458 	int j;
459 
460 	N2PIUPC_DBG2("n2piupc_kstat_fini called\n");
461 
462 	for (j = 0, grp_pp = leaf_grps; *grp_pp != NULL; j++, grp_pp++) {
463 		grp_p = *grp_pp;
464 		if (grp_p->name_kstats_pp != NULL) {
465 			n2piupc_delete_name_kstats(grp_p->name_kstats_pp,
466 			    grp_p->num_counters);
467 			kmem_free(grp_p->name_kstats_pp,
468 			    grp_p->num_counters * sizeof (kstat_t));
469 			grp_p->name_kstats_pp = NULL;
470 		}
471 	}
472 }
473 
474 static void
475 n2piupc_delete_name_kstats(kstat_t **name_kstats_pp, int num_kstats)
476 {
477 	int i;
478 
479 	if (name_kstats_pp != NULL) {
480 		for (i = 0; i < num_kstats; i++) {
481 			if (name_kstats_pp[i] != NULL)
482 				kstat_delete(name_kstats_pp[i]);
483 		}
484 	}
485 }
486 
487 void
488 n2piupc_kstat_detach(n2piupc_t *n2piupc_p)
489 {
490 	n2piu_grp_t **grp_pp;
491 	int i;
492 
493 	N2PIUPC_DBG2("n2piupc_kstat_detach called\n");
494 
495 	for (i = 0, grp_pp = leaf_grps; *grp_pp != NULL; i++, grp_pp++) {
496 		if (n2piupc_p->n2piupc_ksinfo_p[i] != NULL) {
497 			if (n2piupc_p->n2piupc_ksinfo_p[i]->cntr_ksp != NULL)
498 				kstat_delete(
499 				    n2piupc_p->n2piupc_ksinfo_p[i]->cntr_ksp);
500 			kmem_free(n2piupc_p->n2piupc_ksinfo_p[i],
501 			    sizeof (n2piu_ksinfo_t));
502 		}
503 
504 	}
505 
506 	n2piupc_biterr_detach(n2piupc_p->n2piupc_biterr_p);
507 }
508