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