xref: /onnv-gate/usr/src/uts/sun4v/io/n2piupc/n2piupc_kstats.c (revision 3326:4f5ce2d4d4f5)
13299Sschwartz /*
23299Sschwartz  * CDDL HEADER START
33299Sschwartz  *
43299Sschwartz  * The contents of this file are subject to the terms of the
53299Sschwartz  * Common Development and Distribution License (the "License").
63299Sschwartz  * You may not use this file except in compliance with the License.
73299Sschwartz  *
83299Sschwartz  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93299Sschwartz  * or http://www.opensolaris.org/os/licensing.
103299Sschwartz  * See the License for the specific language governing permissions
113299Sschwartz  * and limitations under the License.
123299Sschwartz  *
133299Sschwartz  * When distributing Covered Code, include this CDDL HEADER in each
143299Sschwartz  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153299Sschwartz  * If applicable, add the following below this CDDL HEADER, with the
163299Sschwartz  * fields enclosed by brackets "[]" replaced with your own identifying
173299Sschwartz  * information: Portions Copyright [yyyy] [name of copyright owner]
183299Sschwartz  *
193299Sschwartz  * CDDL HEADER END
203299Sschwartz  */
213299Sschwartz 
223299Sschwartz /*
233299Sschwartz  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
243299Sschwartz  * Use is subject to license terms.
253299Sschwartz  */
263299Sschwartz 
273299Sschwartz #pragma ident	"%Z%%M%	%I%	%E% SMI"
283299Sschwartz 
293299Sschwartz #include <sys/types.h>
303299Sschwartz #include <sys/kstat.h>
313299Sschwartz #include "n2piupc_acc.h"
323299Sschwartz #include "n2piupc_tables.h"
333299Sschwartz #include "n2piupc.h"
343299Sschwartz #include "n2piupc_biterr.h"
353299Sschwartz 
363299Sschwartz #define	PIC_STR_LEN	5	/* Size of a PICx name string. */
373299Sschwartz 
383299Sschwartz static int n2piupc_create_name_kstat(n2piu_grp_t *grp);
393299Sschwartz static void n2piupc_delete_name_kstats(kstat_t **name_kstats_pp,
403299Sschwartz     int num_kstats);
413299Sschwartz static kstat_t *n2piupc_create_cntr_kstat(char *name, int dev_inst,
423299Sschwartz     int (*update)(kstat_t *, int), n2piu_ksinfo_t *ksinfop, int num_pics);
433299Sschwartz static int n2piupc_kstat_update(kstat_t *ksp, int rw);
443299Sschwartz static kstat_t *n2piupc_create_picN_kstat(char *mod_name, int pic,
453299Sschwartz     uint64_t mask, int num_ev, n2piu_event_t *ev_array);
46*3326Sschwartz static int n2piupc_write(n2piupc_t *n2piupc_p, int regid, uint64_t data);
473299Sschwartz 
483299Sschwartz /*
493299Sschwartz  * One-time initialization for this module.
503299Sschwartz  */
513299Sschwartz int
n2piupc_kstat_init()523299Sschwartz n2piupc_kstat_init()
533299Sschwartz {
543299Sschwartz 	n2piu_grp_t **grp_pp;
553299Sschwartz 	n2piu_grp_t *grp_p;
563299Sschwartz 
573299Sschwartz 	N2PIUPC_DBG2("n2piupc: kstat_init: enter\n");
583299Sschwartz 
593299Sschwartz 	/*
603299Sschwartz 	 * Initialize the name kstats for each group, drawing upon the table
613299Sschwartz 	 * for values.
623299Sschwartz 	 */
633299Sschwartz 	for (grp_pp = leaf_grps; *grp_pp != NULL; grp_pp++) {
643299Sschwartz 
653299Sschwartz 		grp_p = *grp_pp;
663299Sschwartz 
673299Sschwartz 		N2PIUPC_DBG2("Setting up group for %s\n", grp_p->grp_name);
683299Sschwartz 
693299Sschwartz 		/* Create basic pic event-type pair. */
703299Sschwartz 		grp_p->name_kstats_pp = kmem_zalloc((grp_p->num_counters *
713299Sschwartz 			sizeof (kstat_t)), KM_SLEEP);
723299Sschwartz 		if (n2piupc_create_name_kstat(grp_p) != DDI_SUCCESS) {
733299Sschwartz 			n2piupc_kstat_fini();
743299Sschwartz 			N2PIUPC_DBG1("n2piupc: init: failure exit\n");
753299Sschwartz 			return (DDI_FAILURE);
763299Sschwartz 		}
773299Sschwartz 	}
783299Sschwartz 
793299Sschwartz 	N2PIUPC_DBG2("n2piupc: kstat_init: success exit\n");
803299Sschwartz 
813299Sschwartz 	return (DDI_SUCCESS);
823299Sschwartz }
833299Sschwartz 
843299Sschwartz /*
853299Sschwartz  * Per-instance initialization for this module.
863299Sschwartz  */
873299Sschwartz int
n2piupc_kstat_attach(n2piupc_t * n2piupc_p)883299Sschwartz n2piupc_kstat_attach(n2piupc_t *n2piupc_p)
893299Sschwartz {
903299Sschwartz 	n2piu_grp_t **grp_pp;
913299Sschwartz 	n2piu_grp_t *grp_p;
923299Sschwartz 	n2piu_ksinfo_t *ksinfo_p;
933299Sschwartz 
943299Sschwartz 	int i;
953299Sschwartz 
963299Sschwartz 	N2PIUPC_DBG2("n2piupc: kstat_attach %d: enter\n",
973299Sschwartz 	    ddi_get_instance(n2piupc_p->n2piupc_dip));
983299Sschwartz 
993299Sschwartz 	/* Initialize biterr module.  Save opaque result. */
1003299Sschwartz 	if (n2piupc_biterr_attach(&n2piupc_p->n2piupc_biterr_p) != DDI_SUCCESS)
1013299Sschwartz 		goto err;
1023299Sschwartz 
1033299Sschwartz 	/* Set up kstats for each group. */
1043299Sschwartz 	for (i = 0, grp_pp = leaf_grps; *grp_pp != NULL; i++, grp_pp++) {
1053299Sschwartz 
1063299Sschwartz 		grp_p = *grp_pp;
1073299Sschwartz 
1083299Sschwartz 		/*
1093299Sschwartz 		 * ksinfo_p keeps all info needed by n2piupc_kstat_update,
1103299Sschwartz 		 * which is fired off asynchronously on demand by the kstat
1113299Sschwartz 		 * framework.
1123299Sschwartz 		 */
1133299Sschwartz 		ksinfo_p = (n2piu_ksinfo_t *)kmem_zalloc(
1143299Sschwartz 		    sizeof (n2piu_ksinfo_t), KM_SLEEP);
1153299Sschwartz 
1163299Sschwartz 		ksinfo_p->n2piupc_p = n2piupc_p;
1173299Sschwartz 		ksinfo_p->grp_p  = grp_p;
1183299Sschwartz 
1193299Sschwartz 		/* Also save in state structure, for later cleanup. */
1203299Sschwartz 		n2piupc_p->n2piupc_ksinfo_p[i] = ksinfo_p;
1213299Sschwartz 
1223299Sschwartz 		/* Create counter kstats */
1233299Sschwartz 		ksinfo_p->cntr_ksp = n2piupc_create_cntr_kstat(grp_p->grp_name,
1243299Sschwartz 		    ddi_get_instance(n2piupc_p->n2piupc_dip),
1253299Sschwartz 		    n2piupc_kstat_update, ksinfo_p, grp_p->num_counters);
1263299Sschwartz 		if (ksinfo_p->cntr_ksp == NULL)
1273299Sschwartz 			goto err;
1283299Sschwartz 	}
1293299Sschwartz 
130*3326Sschwartz 	/*
131*3326Sschwartz 	 * Special treatment for bit err registers: enable them so they start
132*3326Sschwartz 	 * counting now.
133*3326Sschwartz 	 */
134*3326Sschwartz 	if (n2piupc_write(n2piupc_p, leaf_grps[BIT_ERR_GRP]->regsel_p->regoff,
135*3326Sschwartz 	    BTERR_CTR_ENABLE) != SUCCESS) {
136*3326Sschwartz 		goto err;
137*3326Sschwartz 	}
138*3326Sschwartz 
1393299Sschwartz 	N2PIUPC_DBG2("n2piupc: kstat_attach: success exit\n");
1403299Sschwartz 	return (DDI_SUCCESS);
1413299Sschwartz err:
1423299Sschwartz 	n2piupc_kstat_detach(n2piupc_p);
1433299Sschwartz 	N2PIUPC_DBG2("n2piupc: kstat_attach: failure exit\n");
1443299Sschwartz 	return (DDI_FAILURE);
1453299Sschwartz }
1463299Sschwartz 
1473299Sschwartz /*
1483299Sschwartz  * Create the name kstats for each group.
1493299Sschwartz  */
1503299Sschwartz static int
n2piupc_create_name_kstat(n2piu_grp_t * grp_p)1513299Sschwartz n2piupc_create_name_kstat(n2piu_grp_t *grp_p)
1523299Sschwartz {
1533299Sschwartz 	int i;
1543299Sschwartz 
1553299Sschwartz 	for (i = 0; i < grp_p->num_counters; i++) {
1563299Sschwartz 		grp_p->name_kstats_pp[i] = n2piupc_create_picN_kstat(
1573299Sschwartz 		    grp_p->grp_name, i,
1583299Sschwartz 		    grp_p->regsel_p->fields_p[i].event_offset,
1593299Sschwartz 		    grp_p->regsel_p->fields_p[i].num_events,
1603299Sschwartz 		    grp_p->regsel_p->fields_p[i].events_p);
1613299Sschwartz 
1623299Sschwartz 		if (grp_p->name_kstats_pp[i] == NULL)
1633299Sschwartz 			return (DDI_FAILURE);
1643299Sschwartz 	}
1653299Sschwartz 	return (DDI_SUCCESS);
1663299Sschwartz }
1673299Sschwartz 
1683299Sschwartz /*
1693299Sschwartz  * Create the picN kstat. Returns a pointer to the
1703299Sschwartz  * kstat which the driver must store to allow it
1713299Sschwartz  * to be deleted when necessary.
1723299Sschwartz  */
1733299Sschwartz static kstat_t *
n2piupc_create_picN_kstat(char * mod_name,int pic,uint64_t ev_offset,int num_ev,n2piu_event_t * ev_array)1743299Sschwartz n2piupc_create_picN_kstat(char *mod_name, int pic, uint64_t ev_offset,
1753299Sschwartz     int num_ev, n2piu_event_t *ev_array)
1763299Sschwartz {
1773299Sschwartz 	int event;
1783299Sschwartz 	char pic_name[PIC_STR_LEN];
1793299Sschwartz 	kstat_t	*picN_ksp = NULL;
1803299Sschwartz 	struct kstat_named *pic_named_data;
1813299Sschwartz 
1823299Sschwartz 
1833299Sschwartz 	(void) snprintf(pic_name, PIC_STR_LEN, "pic%1d", pic);
1843299Sschwartz 
1853299Sschwartz 	if ((picN_ksp = kstat_create(mod_name, 0, pic_name,
1863299Sschwartz 	    "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) {
1873299Sschwartz 		cmn_err(CE_WARN, "%s %s : kstat create failed",
1883299Sschwartz 		    mod_name, pic_name);
1893299Sschwartz 		return (NULL);
1903299Sschwartz 	}
1913299Sschwartz 
1923299Sschwartz 	/* NOTE: Number of events is assumed to always be non-zero. */
1933299Sschwartz 
1943299Sschwartz 	pic_named_data = (struct kstat_named *)picN_ksp->ks_data;
1953299Sschwartz 
1963299Sschwartz 	/*
1973299Sschwartz 	 * Fill up data section of the kstat
1983299Sschwartz 	 * Write event names and their associated pcr masks.
1993299Sschwartz 	 * num_ev - 1 is because CLEAR_PIC is added separately.
2003299Sschwartz 	 */
2013299Sschwartz 	for (event = 0; event < num_ev - 1; event++) {
2023299Sschwartz 		pic_named_data[event].value.ui64 =
2033299Sschwartz 		    ev_array[event].value << ev_offset;
2043299Sschwartz 
2053299Sschwartz 		kstat_named_init(&pic_named_data[event],
2063299Sschwartz 		    ev_array[event].name, KSTAT_DATA_UINT64);
2073299Sschwartz 	}
2083299Sschwartz 
2093299Sschwartz 	/*
2103299Sschwartz 	 * add the clear_pic entry
2113299Sschwartz 	 */
2123299Sschwartz 	pic_named_data[event].value.ui64 =
2133299Sschwartz 	    (uint64_t)~(ev_array[event].value << ev_offset);
2143299Sschwartz 
2153299Sschwartz 	kstat_named_init(&pic_named_data[event], ev_array[event].name,
2163299Sschwartz 	    KSTAT_DATA_UINT64);
2173299Sschwartz 
2183299Sschwartz 	kstat_install(picN_ksp);
2193299Sschwartz 
2203299Sschwartz 	return (picN_ksp);
2213299Sschwartz }
2223299Sschwartz 
2233299Sschwartz /*
2243299Sschwartz  * Create the "counters" kstat.
2253299Sschwartz  */
2263299Sschwartz static kstat_t *
n2piupc_create_cntr_kstat(char * name,int dev_inst,int (* update)(kstat_t *,int),n2piu_ksinfo_t * ksinfop,int num_pics)2273299Sschwartz n2piupc_create_cntr_kstat(char *name, int dev_inst,
2283299Sschwartz     int (*update)(kstat_t *, int), n2piu_ksinfo_t *ksinfop, int num_pics)
2293299Sschwartz {
2303299Sschwartz 	int i;
2313299Sschwartz 	char pic_str[PIC_STR_LEN];
2323299Sschwartz 	struct kstat *counters_ksp;
2333299Sschwartz 	struct kstat_named *counters_named_data;
2343299Sschwartz 
2353299Sschwartz 	N2PIUPC_DBG2("n2piupc_create_cntr_kstat: name: %s instance: %d\n",
2363299Sschwartz 	    name, dev_inst);
2373299Sschwartz 
2383299Sschwartz 	/*
2393299Sschwartz 	 * Size of kstat is num_pics + 1. extra one for pcr.
2403299Sschwartz 	 */
2413299Sschwartz 
2423299Sschwartz 	if ((counters_ksp = kstat_create(name, dev_inst, "counters", "bus",
2433299Sschwartz 	    KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) {
2443299Sschwartz 		cmn_err(CE_WARN, "%s%d: kstat_create for %s counters failed",
2453299Sschwartz 		    NAMEINST(ksinfop->n2piupc_p->n2piupc_dip), name);
2463299Sschwartz 		return (NULL);
2473299Sschwartz 	}
2483299Sschwartz 
2493299Sschwartz 	counters_named_data = (struct kstat_named *)(counters_ksp->ks_data);
2503299Sschwartz 	kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64);
2513299Sschwartz 
2523299Sschwartz 	for (i = 0; i < num_pics; i++) {
2533299Sschwartz 		(void) snprintf(pic_str, PIC_STR_LEN, "pic%1d", i);
2543299Sschwartz 
2553299Sschwartz 		kstat_named_init(&counters_named_data[i+1], pic_str,
2563299Sschwartz 		    KSTAT_DATA_UINT64);
2573299Sschwartz 	}
2583299Sschwartz 
2593299Sschwartz 	/*
2603299Sschwartz 	 * Store the reg type and other info. in the kstat's private field
2613299Sschwartz 	 * so that they are available to the update function.
2623299Sschwartz 	 */
2633299Sschwartz 	counters_ksp->ks_private = (void *)ksinfop;
2643299Sschwartz 	counters_ksp->ks_update = update;
2653299Sschwartz 
2663299Sschwartz 	kstat_install(counters_ksp);
2673299Sschwartz 
2683299Sschwartz 	return (counters_ksp);
2693299Sschwartz }
2703299Sschwartz 
2713299Sschwartz /* Higher-level register write, hides SW abstractions. */
2723299Sschwartz static int
n2piupc_write(n2piupc_t * n2piupc_p,int regid,uint64_t data)2733299Sschwartz n2piupc_write(n2piupc_t *n2piupc_p, int regid, uint64_t data)
2743299Sschwartz {
2753299Sschwartz 	int rval = SUCCESS;
2763299Sschwartz 
2773299Sschwartz 	switch (regid) {
2783299Sschwartz 	case SW_N2PIU_BITERR_SEL:
2793299Sschwartz 	case SW_N2PIU_BITERR_CLR:
2803299Sschwartz 		rval = n2piupc_biterr_write(n2piupc_p, regid, data);
2813299Sschwartz 		break;
2823299Sschwartz 
2833299Sschwartz 	default:
2843299Sschwartz 		if (n2piupc_set_perfreg(n2piupc_p->n2piupc_handle,
2853299Sschwartz 		    regid, data) != H_EOK)
2863299Sschwartz 			rval = EIO;
2873299Sschwartz 		break;
2883299Sschwartz 	}
2893299Sschwartz 
2903299Sschwartz 	N2PIUPC_DBG1("n2piupc_write: status:%d\n", rval);
2913299Sschwartz 	return (rval);
2923299Sschwartz }
2933299Sschwartz 
2943299Sschwartz 
2953299Sschwartz /* Higher-level register read, hides SW abstractions. */
2963299Sschwartz static int
n2piupc_read(n2piupc_t * n2piupc_p,int regid,uint64_t * data)2973299Sschwartz n2piupc_read(n2piupc_t *n2piupc_p, int regid, uint64_t *data)
2983299Sschwartz {
2993299Sschwartz 	int rval = SUCCESS;
3003299Sschwartz 
3013299Sschwartz 	N2PIUPC_DBG2("n2piupc_read enter: regid:%d\n", regid);
3023299Sschwartz 
3033299Sschwartz 	/* This "register" is a layered SW-implemented reg. */
3043299Sschwartz 	switch (regid) {
3053299Sschwartz 	case SW_N2PIU_BITERR_CNT1_DATA:
3063299Sschwartz 	case SW_N2PIU_BITERR_CNT2_DATA:
3073299Sschwartz 	case SW_N2PIU_BITERR_SEL:
3083299Sschwartz 		rval = n2piupc_biterr_read(n2piupc_p, regid, data);
3093299Sschwartz 		break;
3103299Sschwartz 
3113299Sschwartz 	default:
3123299Sschwartz 		if (n2piupc_get_perfreg(n2piupc_p->n2piupc_handle,
3133299Sschwartz 		    regid, data) != H_EOK)
3143299Sschwartz 			rval = EIO;
3153299Sschwartz 		break;
3163299Sschwartz 	}
3173299Sschwartz 
3183299Sschwartz 	N2PIUPC_DBG1("n2piupc_read exit: data:0x%lx, status:%d\n", *data,
3193299Sschwartz 	    rval);
3203299Sschwartz 
3213299Sschwartz 	return (rval);
3223299Sschwartz }
3233299Sschwartz 
3243299Sschwartz 
3253299Sschwartz /*
3263299Sschwartz  * Program a performance counter.
3273299Sschwartz  *
3283299Sschwartz  * reggroup is which type of counter.
3293299Sschwartz  * counter is the counter number.
3303299Sschwartz  * event is the event to program for that counter.
3313299Sschwartz  */
3323299Sschwartz static int
n2piupc_perfcnt_program(n2piupc_t * n2piupc_p,n2piu_grp_t * grp_p,uint64_t new_events)3333299Sschwartz n2piupc_perfcnt_program(n2piupc_t *n2piupc_p, n2piu_grp_t *grp_p,
3343299Sschwartz     uint64_t new_events)
3353299Sschwartz {
3363299Sschwartz 	uint64_t old_events;
3373299Sschwartz 	int rval = SUCCESS;
3383299Sschwartz 	uint64_t event_mask;
3393299Sschwartz 	int counter;
3403299Sschwartz 
3413299Sschwartz 	N2PIUPC_DBG1(
3423299Sschwartz 	    "n2piupc_perfcnt_program enter: new_events:0x%" PRIx64 "\n",
3433299Sschwartz 	    new_events);
3443299Sschwartz 
3453299Sschwartz 	if ((rval = n2piupc_read(n2piupc_p, grp_p->regsel_p->regoff,
3463299Sschwartz 	    &old_events)) != SUCCESS) {
3473299Sschwartz 		N2PIUPC_DBG1(
3483299Sschwartz 		    "Read of old event data failed, select reg offset:%ld\n",
3493299Sschwartz 		    grp_p->regsel_p->regoff);
3503299Sschwartz 		goto done_pgm;
3513299Sschwartz 	}
3523299Sschwartz 
3533299Sschwartz 	N2PIUPC_DBG1("  old_events:0x%" PRIx64 "\n", old_events);
3543299Sschwartz 
3553299Sschwartz 	for (counter = 0; counter < grp_p->num_counters; counter++) {
3563299Sschwartz 
3573299Sschwartz 		if (grp_p->counters_p[counter].zero_regoff == NO_REGISTER)
3583299Sschwartz 			continue;
3593299Sschwartz 
3603299Sschwartz 		event_mask = grp_p->regsel_p->fields_p[counter].event_mask <<
3613299Sschwartz 		    grp_p->regsel_p->fields_p[counter].event_offset;
3623299Sschwartz 
3633299Sschwartz 		N2PIUPC_DBG1(
3643299Sschwartz 		    "grp:%s, counter:%d, zero_regoff:0x%lx, "
3653299Sschwartz 		    "event_mask:0x%" PRIx64 ", old&mask:0x%lx, "
3663299Sschwartz 		    "new&mask:0x%lx\n",
3673299Sschwartz 		    grp_p->grp_name, counter,
3683299Sschwartz 		    grp_p->counters_p[counter].zero_regoff,
3693299Sschwartz 		    event_mask, old_events & event_mask,
3703299Sschwartz 		    new_events & event_mask);
3713299Sschwartz 
3723299Sschwartz 		if ((old_events & event_mask) ==
3733299Sschwartz 		    (new_events & event_mask))
3743299Sschwartz 			continue;
3753299Sschwartz 
3763299Sschwartz 		N2PIUPC_DBG1("Zeroing counter %d\n", counter);
3773299Sschwartz 		if ((rval = n2piupc_write(n2piupc_p,
3783299Sschwartz 		    grp_p->counters_p[counter].zero_regoff,
3793299Sschwartz 		    grp_p->counters_p[counter].zero_value)) != SUCCESS)
3803299Sschwartz 			goto done_pgm;
3813299Sschwartz 	}
3823299Sschwartz 
3833299Sschwartz 	if (old_events != new_events) {
3843299Sschwartz 		N2PIUPC_DBG1("old != new, setting event reg %ld to 0x%lx\n",
3853299Sschwartz 		    grp_p->regsel_p->regoff, new_events);
3863299Sschwartz 		if ((rval = n2piupc_write(n2piupc_p, grp_p->regsel_p->regoff,
3873299Sschwartz 		    new_events)) != SUCCESS) {
3883299Sschwartz 			N2PIUPC_DBG1(
3893299Sschwartz 			    "Write of new event data failed, "
3903299Sschwartz 			    "select reg offset: %ld\n",
3913299Sschwartz 			    grp_p->regsel_p->regoff);
3923299Sschwartz 			goto done_pgm;
3933299Sschwartz 		}
3943299Sschwartz 	}
3953299Sschwartz done_pgm:
3963299Sschwartz 	N2PIUPC_DBG1("n2piupc_perfcnt_program: returning status %d.\n", rval);
3973299Sschwartz 	return (rval);
3983299Sschwartz }
3993299Sschwartz 
4003299Sschwartz /*
4013299Sschwartz  * kstat update function. Handles reads/writes
4023299Sschwartz  * from/to kstat.
4033299Sschwartz  */
4043299Sschwartz static int
n2piupc_kstat_update(kstat_t * ksp,int rw)4053299Sschwartz n2piupc_kstat_update(kstat_t *ksp, int rw)
4063299Sschwartz {
4073299Sschwartz 	struct kstat_named *data_p;
4083299Sschwartz 	int counter;
4093299Sschwartz 	n2piu_ksinfo_t *ksinfop = ksp->ks_private;
4103299Sschwartz 	n2piu_grp_t *grp_p = ksinfop->grp_p;
4113299Sschwartz 	n2piupc_t *n2piupc_p = ksinfop->n2piupc_p;
4123299Sschwartz 
4133299Sschwartz 	data_p = (struct kstat_named *)ksp->ks_data;
4143299Sschwartz 
4153299Sschwartz 	if (rw == KSTAT_WRITE) {
4163299Sschwartz 
4173299Sschwartz 		N2PIUPC_DBG2("n2piupc_kstat_update: wr %ld\n",
4183299Sschwartz 		    data_p[0].value.ui64);
4193299Sschwartz 
4203299Sschwartz 		/*
4213299Sschwartz 		 * Fields without programmable events won't be zeroed as
4223299Sschwartz 		 * n2piupc_perfcnt_program is what zeros them.
4233299Sschwartz 		 */
4243299Sschwartz 
4253299Sschwartz 		/* This group has programmable events. */
4263299Sschwartz 		if (grp_p->regsel_p->regoff != NO_REGISTER) {
4273299Sschwartz 
4283299Sschwartz 			N2PIUPC_DBG2("write: regoff has valid register\n");
4293299Sschwartz 			if (n2piupc_perfcnt_program(n2piupc_p, grp_p,
4303299Sschwartz 			    data_p[0].value.ui64) != SUCCESS)
4313299Sschwartz 				return (EIO);
4323299Sschwartz 		}
4333299Sschwartz 
4343299Sschwartz 	} else {	/* Read the event register and all of the counters. */
4353299Sschwartz 
4363299Sschwartz 		/* This group has programmable events. */
4373299Sschwartz 		if (grp_p->regsel_p->regoff != NO_REGISTER) {
4383299Sschwartz 
4393299Sschwartz 			N2PIUPC_DBG2("read: regoff has valid register\n");
4403299Sschwartz 			if (n2piupc_read(n2piupc_p, grp_p->regsel_p->regoff,
4413299Sschwartz 			    &data_p[0].value.ui64) != SUCCESS)
4423299Sschwartz 				return (EIO);
4433299Sschwartz 		} else
4443299Sschwartz 			data_p[0].value.ui64 = 0ull;
4453299Sschwartz 
4463299Sschwartz 		N2PIUPC_DBG2("n2piupc_kstat_update: rd event %ld",
4473299Sschwartz 		    data_p[0].value.ui64);
4483299Sschwartz 
4493299Sschwartz 		for (counter = 0; counter < grp_p->num_counters; counter++) {
4503299Sschwartz 			if (n2piupc_read(n2piupc_p,
4513299Sschwartz 			    grp_p->counters_p[counter].regoff,
4523299Sschwartz 			    &data_p[counter + 1].value.ui64) != SUCCESS)
4533299Sschwartz 				return (EIO);
4543299Sschwartz 
4553299Sschwartz 			N2PIUPC_DBG2("cntr%d, off:0x%lx, val:0x%ld", counter,
4563299Sschwartz 			    grp_p->counters_p[counter].regoff,
4573299Sschwartz 			    data_p[counter + 1].value.ui64);
4583299Sschwartz 		}
4593299Sschwartz 	}
4603299Sschwartz 	return (SUCCESS);
4613299Sschwartz }
4623299Sschwartz 
4633299Sschwartz void
n2piupc_kstat_fini()4643299Sschwartz n2piupc_kstat_fini()
4653299Sschwartz {
4663299Sschwartz 	n2piu_grp_t **grp_pp;
4673299Sschwartz 	n2piu_grp_t *grp_p;
4683299Sschwartz 	int j;
4693299Sschwartz 
4703299Sschwartz 	N2PIUPC_DBG2("n2piupc_kstat_fini called\n");
4713299Sschwartz 
4723299Sschwartz 	for (j = 0, grp_pp = leaf_grps; *grp_pp != NULL; j++, grp_pp++) {
4733299Sschwartz 		grp_p = *grp_pp;
4743299Sschwartz 		if (grp_p->name_kstats_pp != NULL) {
4753299Sschwartz 			n2piupc_delete_name_kstats(grp_p->name_kstats_pp,
4763299Sschwartz 			    grp_p->num_counters);
4773299Sschwartz 			kmem_free(grp_p->name_kstats_pp,
4783299Sschwartz 			    grp_p->num_counters * sizeof (kstat_t));
4793299Sschwartz 			grp_p->name_kstats_pp = NULL;
4803299Sschwartz 		}
4813299Sschwartz 	}
4823299Sschwartz }
4833299Sschwartz 
4843299Sschwartz static void
n2piupc_delete_name_kstats(kstat_t ** name_kstats_pp,int num_kstats)4853299Sschwartz n2piupc_delete_name_kstats(kstat_t **name_kstats_pp, int num_kstats)
4863299Sschwartz {
4873299Sschwartz 	int i;
4883299Sschwartz 
4893299Sschwartz 	if (name_kstats_pp != NULL) {
4903299Sschwartz 		for (i = 0; i < num_kstats; i++) {
4913299Sschwartz 			if (name_kstats_pp[i] != NULL)
4923299Sschwartz 				kstat_delete(name_kstats_pp[i]);
4933299Sschwartz 		}
4943299Sschwartz 	}
4953299Sschwartz }
4963299Sschwartz 
4973299Sschwartz void
n2piupc_kstat_detach(n2piupc_t * n2piupc_p)4983299Sschwartz n2piupc_kstat_detach(n2piupc_t *n2piupc_p)
4993299Sschwartz {
5003299Sschwartz 	n2piu_grp_t **grp_pp;
5013299Sschwartz 	int i;
5023299Sschwartz 
5033299Sschwartz 	N2PIUPC_DBG2("n2piupc_kstat_detach called\n");
5043299Sschwartz 
5053299Sschwartz 	for (i = 0, grp_pp = leaf_grps; *grp_pp != NULL; i++, grp_pp++) {
5063299Sschwartz 		if (n2piupc_p->n2piupc_ksinfo_p[i] != NULL) {
5073299Sschwartz 			if (n2piupc_p->n2piupc_ksinfo_p[i]->cntr_ksp != NULL)
5083299Sschwartz 				kstat_delete(
5093299Sschwartz 				    n2piupc_p->n2piupc_ksinfo_p[i]->cntr_ksp);
5103299Sschwartz 			kmem_free(n2piupc_p->n2piupc_ksinfo_p[i],
5113299Sschwartz 			    sizeof (n2piu_ksinfo_t));
5123299Sschwartz 		}
5133299Sschwartz 
5143299Sschwartz 	}
5153299Sschwartz 
5163299Sschwartz 	n2piupc_biterr_detach(n2piupc_p->n2piupc_biterr_p);
5173299Sschwartz }
518