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