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