1*4df55fdeSJanie Lu /* 2*4df55fdeSJanie Lu * CDDL HEADER START 3*4df55fdeSJanie Lu * 4*4df55fdeSJanie Lu * The contents of this file are subject to the terms of the 5*4df55fdeSJanie Lu * Common Development and Distribution License (the "License"). 6*4df55fdeSJanie Lu * You may not use this file except in compliance with the License. 7*4df55fdeSJanie Lu * 8*4df55fdeSJanie Lu * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*4df55fdeSJanie Lu * or http://www.opensolaris.org/os/licensing. 10*4df55fdeSJanie Lu * See the License for the specific language governing permissions 11*4df55fdeSJanie Lu * and limitations under the License. 12*4df55fdeSJanie Lu * 13*4df55fdeSJanie Lu * When distributing Covered Code, include this CDDL HEADER in each 14*4df55fdeSJanie Lu * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*4df55fdeSJanie Lu * If applicable, add the following below this CDDL HEADER, with the 16*4df55fdeSJanie Lu * fields enclosed by brackets "[]" replaced with your own identifying 17*4df55fdeSJanie Lu * information: Portions Copyright [yyyy] [name of copyright owner] 18*4df55fdeSJanie Lu * 19*4df55fdeSJanie Lu * CDDL HEADER END 20*4df55fdeSJanie Lu */ 21*4df55fdeSJanie Lu 22*4df55fdeSJanie Lu /* 23*4df55fdeSJanie Lu * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*4df55fdeSJanie Lu * Use is subject to license terms. 25*4df55fdeSJanie Lu */ 26*4df55fdeSJanie Lu 27*4df55fdeSJanie Lu /* 28*4df55fdeSJanie Lu * IO Performance Counter Driver 29*4df55fdeSJanie Lu */ 30*4df55fdeSJanie Lu 31*4df55fdeSJanie Lu #include <sys/types.h> 32*4df55fdeSJanie Lu #include <sys/ddi.h> 33*4df55fdeSJanie Lu #include <sys/modctl.h> 34*4df55fdeSJanie Lu #include "iospc.h" 35*4df55fdeSJanie Lu 36*4df55fdeSJanie Lu /* Debugging level. */ 37*4df55fdeSJanie Lu #ifdef DEBUG 38*4df55fdeSJanie Lu int iospc_debug = 0; 39*4df55fdeSJanie Lu #endif /* DEBUG */ 40*4df55fdeSJanie Lu 41*4df55fdeSJanie Lu /* State structure anchor. */ 42*4df55fdeSJanie Lu void *iospc_state_p; 43*4df55fdeSJanie Lu 44*4df55fdeSJanie Lu static int iospc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 45*4df55fdeSJanie Lu static int iospc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 46*4df55fdeSJanie Lu static int iospc_create_name_kstat(iospc_grp_t *grp); 47*4df55fdeSJanie Lu static void iospc_delete_name_kstats(kstat_t **name_kstats_pp, 48*4df55fdeSJanie Lu int num_kstats); 49*4df55fdeSJanie Lu static kstat_t *iospc_create_cntr_kstat(char *name, int dev_inst, 50*4df55fdeSJanie Lu int (*update)(kstat_t *, int), iospc_ksinfo_t *ksinfop, int num_pics); 51*4df55fdeSJanie Lu static int iospc_kstat_update(kstat_t *ksp, int rw); 52*4df55fdeSJanie Lu static kstat_t *iospc_create_picN_kstat(char *mod_name, int pic, 53*4df55fdeSJanie Lu uint64_t mask, int num_ev, iospc_event_t *ev_array); 54*4df55fdeSJanie Lu 55*4df55fdeSJanie Lu iospc_grp_t **iospc_leaf_grps = NULL; 56*4df55fdeSJanie Lu int iospc_kstat_inited = 0; 57*4df55fdeSJanie Lu kmutex_t iospc_mutex; 58*4df55fdeSJanie Lu 59*4df55fdeSJanie Lu static struct dev_ops iospc_ops = { 60*4df55fdeSJanie Lu DEVO_REV, 61*4df55fdeSJanie Lu 0, 62*4df55fdeSJanie Lu nulldev, 63*4df55fdeSJanie Lu nulldev, 64*4df55fdeSJanie Lu nulldev, 65*4df55fdeSJanie Lu iospc_attach, 66*4df55fdeSJanie Lu iospc_detach, 67*4df55fdeSJanie Lu nodev, 68*4df55fdeSJanie Lu NULL, 69*4df55fdeSJanie Lu NULL, 70*4df55fdeSJanie Lu nodev 71*4df55fdeSJanie Lu }; 72*4df55fdeSJanie Lu 73*4df55fdeSJanie Lu extern struct mod_ops mod_driverops; 74*4df55fdeSJanie Lu 75*4df55fdeSJanie Lu static struct modldrv md = { 76*4df55fdeSJanie Lu &mod_driverops, 77*4df55fdeSJanie Lu "IO Perf Counter Driver", 78*4df55fdeSJanie Lu &iospc_ops, 79*4df55fdeSJanie Lu }; 80*4df55fdeSJanie Lu 81*4df55fdeSJanie Lu static struct modlinkage ml = { 82*4df55fdeSJanie Lu MODREV_1, 83*4df55fdeSJanie Lu (void *)&md, 84*4df55fdeSJanie Lu NULL 85*4df55fdeSJanie Lu }; 86*4df55fdeSJanie Lu 87*4df55fdeSJanie Lu /* 88*4df55fdeSJanie Lu * One-time module-wide initialization. 89*4df55fdeSJanie Lu */ 90*4df55fdeSJanie Lu int 91*4df55fdeSJanie Lu _init(void) 92*4df55fdeSJanie Lu { 93*4df55fdeSJanie Lu int rval; 94*4df55fdeSJanie Lu 95*4df55fdeSJanie Lu /* Initialize per-leaf soft state pointer. */ 96*4df55fdeSJanie Lu if ((rval = ddi_soft_state_init(&iospc_state_p, 97*4df55fdeSJanie Lu sizeof (iospc_t), 1)) != DDI_SUCCESS) 98*4df55fdeSJanie Lu return (rval); 99*4df55fdeSJanie Lu 100*4df55fdeSJanie Lu /* If all checks out, install the module. */ 101*4df55fdeSJanie Lu if ((rval = mod_install(&ml)) != DDI_SUCCESS) { 102*4df55fdeSJanie Lu ddi_soft_state_fini(&iospc_state_p); 103*4df55fdeSJanie Lu return (rval); 104*4df55fdeSJanie Lu } 105*4df55fdeSJanie Lu mutex_init(&iospc_mutex, NULL, MUTEX_DRIVER, NULL); 106*4df55fdeSJanie Lu return (DDI_SUCCESS); 107*4df55fdeSJanie Lu } 108*4df55fdeSJanie Lu 109*4df55fdeSJanie Lu /* 110*4df55fdeSJanie Lu * One-time module-wide cleanup, after last detach is done. 111*4df55fdeSJanie Lu */ 112*4df55fdeSJanie Lu int 113*4df55fdeSJanie Lu _fini(void) 114*4df55fdeSJanie Lu { 115*4df55fdeSJanie Lu int rval; 116*4df55fdeSJanie Lu 117*4df55fdeSJanie Lu /* 118*4df55fdeSJanie Lu * Remove the module first as this operation is the only thing here 119*4df55fdeSJanie Lu * which can fail. 120*4df55fdeSJanie Lu */ 121*4df55fdeSJanie Lu rval = mod_remove(&ml); 122*4df55fdeSJanie Lu if (rval != DDI_SUCCESS) 123*4df55fdeSJanie Lu return (rval); 124*4df55fdeSJanie Lu 125*4df55fdeSJanie Lu if (iospc_leaf_grps != NULL) { 126*4df55fdeSJanie Lu iospc_kstat_fini(); 127*4df55fdeSJanie Lu mutex_enter(&iospc_mutex); 128*4df55fdeSJanie Lu iospc_kstat_inited = 0; 129*4df55fdeSJanie Lu (void) rfios_unbind_group(); 130*4df55fdeSJanie Lu iospc_leaf_grps = NULL; 131*4df55fdeSJanie Lu mutex_exit(&iospc_mutex); 132*4df55fdeSJanie Lu } 133*4df55fdeSJanie Lu 134*4df55fdeSJanie Lu mutex_destroy(&iospc_mutex); 135*4df55fdeSJanie Lu 136*4df55fdeSJanie Lu /* Free px soft state */ 137*4df55fdeSJanie Lu ddi_soft_state_fini(&iospc_state_p); 138*4df55fdeSJanie Lu 139*4df55fdeSJanie Lu return (DDI_SUCCESS); 140*4df55fdeSJanie Lu } 141*4df55fdeSJanie Lu 142*4df55fdeSJanie Lu int 143*4df55fdeSJanie Lu _info(struct modinfo *modinfop) 144*4df55fdeSJanie Lu { 145*4df55fdeSJanie Lu return (mod_info(&ml, modinfop)); 146*4df55fdeSJanie Lu } 147*4df55fdeSJanie Lu 148*4df55fdeSJanie Lu /* 149*4df55fdeSJanie Lu * Per-instance initialization. Suspend/resume not supported. 150*4df55fdeSJanie Lu */ 151*4df55fdeSJanie Lu static int 152*4df55fdeSJanie Lu iospc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 153*4df55fdeSJanie Lu { 154*4df55fdeSJanie Lu iospc_t *iospc_p; 155*4df55fdeSJanie Lu int instance = ddi_get_instance(dip); 156*4df55fdeSJanie Lu char *ptr; 157*4df55fdeSJanie Lu 158*4df55fdeSJanie Lu IOSPC_DBG2("iospc: iospc_attach: enter\n"); 159*4df55fdeSJanie Lu switch (cmd) { 160*4df55fdeSJanie Lu case DDI_RESUME: 161*4df55fdeSJanie Lu case DDI_ATTACH: 162*4df55fdeSJanie Lu /* Initialize one-time kstat structures. */ 163*4df55fdeSJanie Lu mutex_enter(&iospc_mutex); 164*4df55fdeSJanie Lu if (!iospc_kstat_inited) { 165*4df55fdeSJanie Lu if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 166*4df55fdeSJanie Lu 0, "compatible", &ptr)) != DDI_PROP_SUCCESS) 167*4df55fdeSJanie Lu goto bad_property; 168*4df55fdeSJanie Lu 169*4df55fdeSJanie Lu if ((strcmp(ptr, "SUNW,ktios-pr") == 0) || 170*4df55fdeSJanie Lu (strcmp(ptr, "SUNW,rfios-pr") == 0)) { 171*4df55fdeSJanie Lu iospc_leaf_grps = rfios_bind_group(); 172*4df55fdeSJanie Lu } else { 173*4df55fdeSJanie Lu ddi_prop_free(ptr); 174*4df55fdeSJanie Lu goto bad_property; 175*4df55fdeSJanie Lu } 176*4df55fdeSJanie Lu 177*4df55fdeSJanie Lu ddi_prop_free(ptr); 178*4df55fdeSJanie Lu 179*4df55fdeSJanie Lu if (iospc_kstat_init() != DDI_SUCCESS) 180*4df55fdeSJanie Lu goto bad_kstat_init; 181*4df55fdeSJanie Lu 182*4df55fdeSJanie Lu iospc_kstat_inited++; 183*4df55fdeSJanie Lu } 184*4df55fdeSJanie Lu mutex_exit(&iospc_mutex); 185*4df55fdeSJanie Lu 186*4df55fdeSJanie Lu if (ddi_soft_state_zalloc(iospc_state_p, instance) != 187*4df55fdeSJanie Lu DDI_SUCCESS) { 188*4df55fdeSJanie Lu goto bad_softstate; 189*4df55fdeSJanie Lu } 190*4df55fdeSJanie Lu 191*4df55fdeSJanie Lu iospc_p = (iospc_t *)ddi_get_soft_state(iospc_state_p, 192*4df55fdeSJanie Lu instance); 193*4df55fdeSJanie Lu 194*4df55fdeSJanie Lu iospc_p->iospc_dip = dip; 195*4df55fdeSJanie Lu 196*4df55fdeSJanie Lu /* Set up kstats. */ 197*4df55fdeSJanie Lu 198*4df55fdeSJanie Lu if (iospc_kstat_attach(iospc_p) != DDI_SUCCESS) 199*4df55fdeSJanie Lu goto bad_kstat_attach; 200*4df55fdeSJanie Lu 201*4df55fdeSJanie Lu IOSPC_DBG2("iospc: iospc_attach: exit SUCCESS\n"); 202*4df55fdeSJanie Lu 203*4df55fdeSJanie Lu return (DDI_SUCCESS); 204*4df55fdeSJanie Lu 205*4df55fdeSJanie Lu bad_kstat_attach: 206*4df55fdeSJanie Lu (void) ddi_soft_state_free(iospc_state_p, instance); 207*4df55fdeSJanie Lu bad_softstate: 208*4df55fdeSJanie Lu iospc_kstat_fini(); 209*4df55fdeSJanie Lu bad_kstat_init: 210*4df55fdeSJanie Lu bad_property: 211*4df55fdeSJanie Lu mutex_enter(&iospc_mutex); 212*4df55fdeSJanie Lu IOSPC_DBG2("iospc: iospc_attach: exit FAILURE\n"); 213*4df55fdeSJanie Lu return (DDI_FAILURE); 214*4df55fdeSJanie Lu 215*4df55fdeSJanie Lu default: 216*4df55fdeSJanie Lu return (DDI_FAILURE); 217*4df55fdeSJanie Lu } 218*4df55fdeSJanie Lu } 219*4df55fdeSJanie Lu 220*4df55fdeSJanie Lu /* 221*4df55fdeSJanie Lu * Per-instance cleanup. Suspend/resume not supported. 222*4df55fdeSJanie Lu */ 223*4df55fdeSJanie Lu static int 224*4df55fdeSJanie Lu iospc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 225*4df55fdeSJanie Lu { 226*4df55fdeSJanie Lu int instance = ddi_get_instance(dip); 227*4df55fdeSJanie Lu 228*4df55fdeSJanie Lu IOSPC_DBG2("iospc: iospc_detach: enter\n"); 229*4df55fdeSJanie Lu iospc_t *iospc_p = (iospc_t *)ddi_get_soft_state( 230*4df55fdeSJanie Lu iospc_state_p, instance); 231*4df55fdeSJanie Lu 232*4df55fdeSJanie Lu switch (cmd) { 233*4df55fdeSJanie Lu case DDI_SUSPEND: 234*4df55fdeSJanie Lu case DDI_DETACH: 235*4df55fdeSJanie Lu iospc_kstat_detach(iospc_p); 236*4df55fdeSJanie Lu (void) ddi_soft_state_free(iospc_state_p, instance); 237*4df55fdeSJanie Lu 238*4df55fdeSJanie Lu IOSPC_DBG2("iospc: iospc_detach: exit - SUCCESS\n"); 239*4df55fdeSJanie Lu return (DDI_SUCCESS); 240*4df55fdeSJanie Lu 241*4df55fdeSJanie Lu default: 242*4df55fdeSJanie Lu IOSPC_DBG2("iospc: iospc_detach: exit - FAILURE\n"); 243*4df55fdeSJanie Lu return (DDI_FAILURE); 244*4df55fdeSJanie Lu } 245*4df55fdeSJanie Lu } 246*4df55fdeSJanie Lu 247*4df55fdeSJanie Lu #define PIC_STR_LEN 5 /* Size of a PICx name string. */ 248*4df55fdeSJanie Lu 249*4df55fdeSJanie Lu /* 250*4df55fdeSJanie Lu * One-time initialization for this module. 251*4df55fdeSJanie Lu */ 252*4df55fdeSJanie Lu int 253*4df55fdeSJanie Lu iospc_kstat_init() 254*4df55fdeSJanie Lu { 255*4df55fdeSJanie Lu iospc_grp_t **grp_pp; 256*4df55fdeSJanie Lu iospc_grp_t *grp_p; 257*4df55fdeSJanie Lu 258*4df55fdeSJanie Lu IOSPC_DBG2("iospc: kstat_init: enter\n"); 259*4df55fdeSJanie Lu 260*4df55fdeSJanie Lu /* 261*4df55fdeSJanie Lu * Initialize the name kstats for each group, drawing upon the table 262*4df55fdeSJanie Lu * for values. 263*4df55fdeSJanie Lu */ 264*4df55fdeSJanie Lu for (grp_pp = iospc_leaf_grps; *grp_pp != NULL; grp_pp++) { 265*4df55fdeSJanie Lu 266*4df55fdeSJanie Lu grp_p = *grp_pp; 267*4df55fdeSJanie Lu 268*4df55fdeSJanie Lu IOSPC_DBG2("Setting up group for %s\n", grp_p->grp_name); 269*4df55fdeSJanie Lu 270*4df55fdeSJanie Lu /* Create basic pic event-type pair. */ 271*4df55fdeSJanie Lu grp_p->name_kstats_pp = kmem_zalloc((grp_p->num_counters * 272*4df55fdeSJanie Lu sizeof (kstat_t)), KM_SLEEP); 273*4df55fdeSJanie Lu if (iospc_create_name_kstat(grp_p) != DDI_SUCCESS) { 274*4df55fdeSJanie Lu iospc_kstat_fini(); 275*4df55fdeSJanie Lu IOSPC_DBG1("iospc: init: failure exit\n"); 276*4df55fdeSJanie Lu return (DDI_FAILURE); 277*4df55fdeSJanie Lu } 278*4df55fdeSJanie Lu } 279*4df55fdeSJanie Lu 280*4df55fdeSJanie Lu IOSPC_DBG2("iospc: kstat_init: success exit\n"); 281*4df55fdeSJanie Lu 282*4df55fdeSJanie Lu return (DDI_SUCCESS); 283*4df55fdeSJanie Lu } 284*4df55fdeSJanie Lu 285*4df55fdeSJanie Lu /* 286*4df55fdeSJanie Lu * Per-instance initialization for this module. 287*4df55fdeSJanie Lu */ 288*4df55fdeSJanie Lu int 289*4df55fdeSJanie Lu iospc_kstat_attach(iospc_t *iospc_p) 290*4df55fdeSJanie Lu { 291*4df55fdeSJanie Lu iospc_grp_t **grp_pp; 292*4df55fdeSJanie Lu iospc_grp_t *grp_p; 293*4df55fdeSJanie Lu iospc_ksinfo_t *ksinfo_p; 294*4df55fdeSJanie Lu 295*4df55fdeSJanie Lu int i; 296*4df55fdeSJanie Lu 297*4df55fdeSJanie Lu IOSPC_DBG2("iospc: kstat_attach %d: enter\n", 298*4df55fdeSJanie Lu ddi_get_instance(iospc_p->iospc_dip)); 299*4df55fdeSJanie Lu 300*4df55fdeSJanie Lu /* Set up kstats for each group. */ 301*4df55fdeSJanie Lu for (i = 0, grp_pp = iospc_leaf_grps; *grp_pp != NULL; i++, grp_pp++) { 302*4df55fdeSJanie Lu 303*4df55fdeSJanie Lu if (i >= IOSPC_MAX_NUM_GRPS) 304*4df55fdeSJanie Lu goto err; 305*4df55fdeSJanie Lu 306*4df55fdeSJanie Lu grp_p = *grp_pp; 307*4df55fdeSJanie Lu 308*4df55fdeSJanie Lu /* 309*4df55fdeSJanie Lu * ksinfo_p keeps all info needed by iospc_kstat_update, 310*4df55fdeSJanie Lu * which is fired off asynchronously on demand by the kstat 311*4df55fdeSJanie Lu * framework. 312*4df55fdeSJanie Lu */ 313*4df55fdeSJanie Lu ksinfo_p = (iospc_ksinfo_t *)kmem_zalloc( 314*4df55fdeSJanie Lu sizeof (iospc_ksinfo_t), KM_SLEEP); 315*4df55fdeSJanie Lu 316*4df55fdeSJanie Lu ksinfo_p->iospc_p = iospc_p; 317*4df55fdeSJanie Lu ksinfo_p->grp_p = grp_p; 318*4df55fdeSJanie Lu 319*4df55fdeSJanie Lu /* Also save in state structure, for later cleanup. */ 320*4df55fdeSJanie Lu iospc_p->iospc_ksinfo_p[i] = ksinfo_p; 321*4df55fdeSJanie Lu 322*4df55fdeSJanie Lu /* Create counter kstats */ 323*4df55fdeSJanie Lu ksinfo_p->cntr_ksp = iospc_create_cntr_kstat(grp_p->grp_name, 324*4df55fdeSJanie Lu ddi_get_instance(iospc_p->iospc_dip), 325*4df55fdeSJanie Lu iospc_kstat_update, ksinfo_p, grp_p->num_counters); 326*4df55fdeSJanie Lu 327*4df55fdeSJanie Lu if (ksinfo_p->cntr_ksp == NULL) 328*4df55fdeSJanie Lu goto err; 329*4df55fdeSJanie Lu 330*4df55fdeSJanie Lu if (grp_p->access_init(iospc_p, ksinfo_p) != SUCCESS) 331*4df55fdeSJanie Lu goto err; 332*4df55fdeSJanie Lu } 333*4df55fdeSJanie Lu 334*4df55fdeSJanie Lu IOSPC_DBG2("iospc: kstat_attach: success exit\n"); 335*4df55fdeSJanie Lu return (DDI_SUCCESS); 336*4df55fdeSJanie Lu err: 337*4df55fdeSJanie Lu iospc_kstat_detach(iospc_p); 338*4df55fdeSJanie Lu IOSPC_DBG2("iospc: kstat_attach: failure exit\n"); 339*4df55fdeSJanie Lu return (DDI_FAILURE); 340*4df55fdeSJanie Lu } 341*4df55fdeSJanie Lu 342*4df55fdeSJanie Lu /* 343*4df55fdeSJanie Lu * Create the name kstats for each group. 344*4df55fdeSJanie Lu */ 345*4df55fdeSJanie Lu static int 346*4df55fdeSJanie Lu iospc_create_name_kstat(iospc_grp_t *grp_p) 347*4df55fdeSJanie Lu { 348*4df55fdeSJanie Lu int i; 349*4df55fdeSJanie Lu 350*4df55fdeSJanie Lu for (i = 0; i < grp_p->num_counters; i++) { 351*4df55fdeSJanie Lu grp_p->name_kstats_pp[i] = iospc_create_picN_kstat( 352*4df55fdeSJanie Lu grp_p->grp_name, i, 353*4df55fdeSJanie Lu grp_p->regsel_p->fields_p[i].event_offset, 354*4df55fdeSJanie Lu grp_p->regsel_p->fields_p[i].num_events, 355*4df55fdeSJanie Lu grp_p->regsel_p->fields_p[i].events_p); 356*4df55fdeSJanie Lu 357*4df55fdeSJanie Lu if (grp_p->name_kstats_pp[i] == NULL) 358*4df55fdeSJanie Lu return (DDI_FAILURE); 359*4df55fdeSJanie Lu } 360*4df55fdeSJanie Lu return (DDI_SUCCESS); 361*4df55fdeSJanie Lu } 362*4df55fdeSJanie Lu 363*4df55fdeSJanie Lu /* 364*4df55fdeSJanie Lu * Create the picN kstat. Returns a pointer to the 365*4df55fdeSJanie Lu * kstat which the driver must store to allow it 366*4df55fdeSJanie Lu * to be deleted when necessary. 367*4df55fdeSJanie Lu */ 368*4df55fdeSJanie Lu static kstat_t * 369*4df55fdeSJanie Lu iospc_create_picN_kstat(char *mod_name, int pic, uint64_t ev_offset, 370*4df55fdeSJanie Lu int num_ev, iospc_event_t *ev_array) 371*4df55fdeSJanie Lu { 372*4df55fdeSJanie Lu int event; 373*4df55fdeSJanie Lu char pic_name[PIC_STR_LEN]; 374*4df55fdeSJanie Lu kstat_t *picN_ksp = NULL; 375*4df55fdeSJanie Lu struct kstat_named *pic_named_data; 376*4df55fdeSJanie Lu 377*4df55fdeSJanie Lu (void) snprintf(pic_name, PIC_STR_LEN, "pic%1d", pic); 378*4df55fdeSJanie Lu 379*4df55fdeSJanie Lu if ((picN_ksp = kstat_create(mod_name, 0, pic_name, 380*4df55fdeSJanie Lu "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) { 381*4df55fdeSJanie Lu return (NULL); 382*4df55fdeSJanie Lu } 383*4df55fdeSJanie Lu 384*4df55fdeSJanie Lu /* NOTE: Number of events is assumed to always be non-zero. */ 385*4df55fdeSJanie Lu 386*4df55fdeSJanie Lu pic_named_data = (struct kstat_named *)picN_ksp->ks_data; 387*4df55fdeSJanie Lu 388*4df55fdeSJanie Lu /* 389*4df55fdeSJanie Lu * Fill up data section of the kstat 390*4df55fdeSJanie Lu * Write event names and their associated pcr masks. 391*4df55fdeSJanie Lu * num_ev - 1 is because CLEAR_PIC is added separately. 392*4df55fdeSJanie Lu */ 393*4df55fdeSJanie Lu for (event = 0; event < num_ev - 1; event++) { 394*4df55fdeSJanie Lu pic_named_data[event].value.ui64 = 395*4df55fdeSJanie Lu ev_array[event].value << ev_offset; 396*4df55fdeSJanie Lu 397*4df55fdeSJanie Lu kstat_named_init(&pic_named_data[event], 398*4df55fdeSJanie Lu ev_array[event].name, KSTAT_DATA_UINT64); 399*4df55fdeSJanie Lu } 400*4df55fdeSJanie Lu 401*4df55fdeSJanie Lu /* 402*4df55fdeSJanie Lu * add the clear_pic entry 403*4df55fdeSJanie Lu */ 404*4df55fdeSJanie Lu pic_named_data[event].value.ui64 = 405*4df55fdeSJanie Lu (uint64_t)~(ev_array[event].value << ev_offset); 406*4df55fdeSJanie Lu 407*4df55fdeSJanie Lu kstat_named_init(&pic_named_data[event], ev_array[event].name, 408*4df55fdeSJanie Lu KSTAT_DATA_UINT64); 409*4df55fdeSJanie Lu 410*4df55fdeSJanie Lu kstat_install(picN_ksp); 411*4df55fdeSJanie Lu 412*4df55fdeSJanie Lu return (picN_ksp); 413*4df55fdeSJanie Lu } 414*4df55fdeSJanie Lu 415*4df55fdeSJanie Lu /* 416*4df55fdeSJanie Lu * Create the "counters" kstat. 417*4df55fdeSJanie Lu */ 418*4df55fdeSJanie Lu static kstat_t * 419*4df55fdeSJanie Lu iospc_create_cntr_kstat(char *name, int dev_inst, 420*4df55fdeSJanie Lu int (*update)(kstat_t *, int), iospc_ksinfo_t *ksinfop, int num_pics) 421*4df55fdeSJanie Lu { 422*4df55fdeSJanie Lu int i; 423*4df55fdeSJanie Lu char pic_str[PIC_STR_LEN]; 424*4df55fdeSJanie Lu struct kstat *counters_ksp; 425*4df55fdeSJanie Lu struct kstat_named *counters_named_data; 426*4df55fdeSJanie Lu 427*4df55fdeSJanie Lu IOSPC_DBG2("iospc_create_cntr_kstat: name: %s instance: %d\n", 428*4df55fdeSJanie Lu name, dev_inst); 429*4df55fdeSJanie Lu 430*4df55fdeSJanie Lu /* 431*4df55fdeSJanie Lu * Size of kstat is num_pics + 1. extra one for pcr. 432*4df55fdeSJanie Lu */ 433*4df55fdeSJanie Lu 434*4df55fdeSJanie Lu if ((counters_ksp = kstat_create(name, dev_inst, "counters", "bus", 435*4df55fdeSJanie Lu KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) { 436*4df55fdeSJanie Lu return (NULL); 437*4df55fdeSJanie Lu } 438*4df55fdeSJanie Lu 439*4df55fdeSJanie Lu counters_named_data = (struct kstat_named *)(counters_ksp->ks_data); 440*4df55fdeSJanie Lu kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64); 441*4df55fdeSJanie Lu 442*4df55fdeSJanie Lu for (i = 0; i < num_pics; i++) { 443*4df55fdeSJanie Lu (void) snprintf(pic_str, PIC_STR_LEN, "pic%1d", i); 444*4df55fdeSJanie Lu 445*4df55fdeSJanie Lu kstat_named_init(&counters_named_data[i+1], pic_str, 446*4df55fdeSJanie Lu KSTAT_DATA_UINT64); 447*4df55fdeSJanie Lu } 448*4df55fdeSJanie Lu 449*4df55fdeSJanie Lu /* 450*4df55fdeSJanie Lu * Store the reg type and other info. in the kstat's private field 451*4df55fdeSJanie Lu * so that they are available to the update function. 452*4df55fdeSJanie Lu */ 453*4df55fdeSJanie Lu counters_ksp->ks_private = (void *)ksinfop; 454*4df55fdeSJanie Lu counters_ksp->ks_update = update; 455*4df55fdeSJanie Lu 456*4df55fdeSJanie Lu kstat_install(counters_ksp); 457*4df55fdeSJanie Lu 458*4df55fdeSJanie Lu return (counters_ksp); 459*4df55fdeSJanie Lu } 460*4df55fdeSJanie Lu 461*4df55fdeSJanie Lu /* 462*4df55fdeSJanie Lu * Program a performance counter. 463*4df55fdeSJanie Lu * 464*4df55fdeSJanie Lu * reggroup is which type of counter. 465*4df55fdeSJanie Lu * counter is the counter number. 466*4df55fdeSJanie Lu * event is the event to program for that counter. 467*4df55fdeSJanie Lu */ 468*4df55fdeSJanie Lu static int 469*4df55fdeSJanie Lu iospc_perfcnt_program(iospc_t *iospc_p, iospc_grp_t *grp_p, 470*4df55fdeSJanie Lu iospc_ksinfo_t *ksinfo_p, uint64_t new_events) 471*4df55fdeSJanie Lu { 472*4df55fdeSJanie Lu uint64_t old_events; 473*4df55fdeSJanie Lu int rval = SUCCESS; 474*4df55fdeSJanie Lu uint64_t event_mask; 475*4df55fdeSJanie Lu int counter; 476*4df55fdeSJanie Lu 477*4df55fdeSJanie Lu IOSPC_DBG1( 478*4df55fdeSJanie Lu "iospc_perfcnt_program enter: new_events:0x%" PRIx64 "\n", 479*4df55fdeSJanie Lu new_events); 480*4df55fdeSJanie Lu 481*4df55fdeSJanie Lu if ((rval = grp_p->access(iospc_p, ksinfo_p->arg, IOSPC_REG_READ, 482*4df55fdeSJanie Lu grp_p->regsel_p->regoff, &old_events)) != SUCCESS) 483*4df55fdeSJanie Lu goto done_pgm; 484*4df55fdeSJanie Lu 485*4df55fdeSJanie Lu IOSPC_DBG1(" old_events:0x%" PRIx64 "\n", old_events); 486*4df55fdeSJanie Lu 487*4df55fdeSJanie Lu for (counter = 0; counter < grp_p->num_counters; counter++) { 488*4df55fdeSJanie Lu 489*4df55fdeSJanie Lu if (grp_p->counters_p[counter].zero_regoff == NO_REGISTER) 490*4df55fdeSJanie Lu continue; 491*4df55fdeSJanie Lu 492*4df55fdeSJanie Lu event_mask = grp_p->regsel_p->fields_p[counter].event_mask << 493*4df55fdeSJanie Lu grp_p->regsel_p->fields_p[counter].event_offset; 494*4df55fdeSJanie Lu 495*4df55fdeSJanie Lu IOSPC_DBG1( 496*4df55fdeSJanie Lu "grp:%s, counter:%d, zero_regoff:0x%lx, " 497*4df55fdeSJanie Lu "event_mask:0x%" PRIx64 ", old&mask:0x%lx, " 498*4df55fdeSJanie Lu "new&mask:0x%lx\n", 499*4df55fdeSJanie Lu grp_p->grp_name, counter, 500*4df55fdeSJanie Lu grp_p->counters_p[counter].zero_regoff, 501*4df55fdeSJanie Lu event_mask, old_events & event_mask, 502*4df55fdeSJanie Lu new_events & event_mask); 503*4df55fdeSJanie Lu 504*4df55fdeSJanie Lu if ((old_events & event_mask) == 505*4df55fdeSJanie Lu (new_events & event_mask)) 506*4df55fdeSJanie Lu continue; 507*4df55fdeSJanie Lu 508*4df55fdeSJanie Lu IOSPC_DBG1("Zeroing counter %d\n", counter); 509*4df55fdeSJanie Lu 510*4df55fdeSJanie Lu if ((rval = grp_p->access(iospc_p, ksinfo_p->arg, 511*4df55fdeSJanie Lu IOSPC_REG_WRITE, grp_p->counters_p[counter].zero_regoff, 512*4df55fdeSJanie Lu &grp_p->counters_p[counter].zero_value)) != SUCCESS) 513*4df55fdeSJanie Lu goto done_pgm; 514*4df55fdeSJanie Lu } 515*4df55fdeSJanie Lu 516*4df55fdeSJanie Lu if (old_events != new_events) { 517*4df55fdeSJanie Lu 518*4df55fdeSJanie Lu IOSPC_DBG1("old != new, setting event reg %ld to 0x%lx\n", 519*4df55fdeSJanie Lu grp_p->regsel_p->regoff, new_events); 520*4df55fdeSJanie Lu 521*4df55fdeSJanie Lu if ((rval = grp_p->access(iospc_p, ksinfo_p->arg, 522*4df55fdeSJanie Lu IOSPC_REG_WRITE, grp_p->regsel_p->regoff, &new_events)) 523*4df55fdeSJanie Lu != SUCCESS) { 524*4df55fdeSJanie Lu IOSPC_DBG1( 525*4df55fdeSJanie Lu "Write of new event data failed, " 526*4df55fdeSJanie Lu "select reg offset: %ld\n", 527*4df55fdeSJanie Lu grp_p->regsel_p->regoff); 528*4df55fdeSJanie Lu goto done_pgm; 529*4df55fdeSJanie Lu } 530*4df55fdeSJanie Lu } 531*4df55fdeSJanie Lu done_pgm: 532*4df55fdeSJanie Lu IOSPC_DBG1("iospc_perfcnt_program: returning status %d.\n", rval); 533*4df55fdeSJanie Lu return (rval); 534*4df55fdeSJanie Lu } 535*4df55fdeSJanie Lu 536*4df55fdeSJanie Lu /* 537*4df55fdeSJanie Lu * kstat update function. Handles reads/writes 538*4df55fdeSJanie Lu * from/to kstat. 539*4df55fdeSJanie Lu */ 540*4df55fdeSJanie Lu static int 541*4df55fdeSJanie Lu iospc_kstat_update(kstat_t *ksp, int rw) 542*4df55fdeSJanie Lu { 543*4df55fdeSJanie Lu struct kstat_named *data_p; 544*4df55fdeSJanie Lu int counter; 545*4df55fdeSJanie Lu iospc_ksinfo_t *ksinfop = ksp->ks_private; 546*4df55fdeSJanie Lu iospc_grp_t *grp_p = ksinfop->grp_p; 547*4df55fdeSJanie Lu iospc_t *iospc_p = ksinfop->iospc_p; 548*4df55fdeSJanie Lu 549*4df55fdeSJanie Lu data_p = (struct kstat_named *)ksp->ks_data; 550*4df55fdeSJanie Lu 551*4df55fdeSJanie Lu if (rw == KSTAT_WRITE) { 552*4df55fdeSJanie Lu 553*4df55fdeSJanie Lu IOSPC_DBG2("iospc_kstat_update: wr %ld\n", 554*4df55fdeSJanie Lu data_p[0].value.ui64); 555*4df55fdeSJanie Lu 556*4df55fdeSJanie Lu /* 557*4df55fdeSJanie Lu * Fields without programmable events won't be zeroed as 558*4df55fdeSJanie Lu * iospc_perfcnt_program is what zeros them. 559*4df55fdeSJanie Lu */ 560*4df55fdeSJanie Lu 561*4df55fdeSJanie Lu /* This group has programmable events. */ 562*4df55fdeSJanie Lu if (grp_p->regsel_p->regoff != NO_REGISTER) { 563*4df55fdeSJanie Lu 564*4df55fdeSJanie Lu IOSPC_DBG2("write: regoff has valid register\n"); 565*4df55fdeSJanie Lu if (iospc_perfcnt_program(iospc_p, grp_p, ksinfop, 566*4df55fdeSJanie Lu data_p[0].value.ui64) != SUCCESS) 567*4df55fdeSJanie Lu return (EIO); 568*4df55fdeSJanie Lu } 569*4df55fdeSJanie Lu 570*4df55fdeSJanie Lu } else { /* Read the event register and all of the counters. */ 571*4df55fdeSJanie Lu 572*4df55fdeSJanie Lu /* This group has programmable events. */ 573*4df55fdeSJanie Lu if (grp_p->regsel_p->regoff != NO_REGISTER) { 574*4df55fdeSJanie Lu 575*4df55fdeSJanie Lu IOSPC_DBG2("read: regoff has valid register\n"); 576*4df55fdeSJanie Lu 577*4df55fdeSJanie Lu if (grp_p->access(iospc_p, ksinfop->arg, IOSPC_REG_READ, 578*4df55fdeSJanie Lu grp_p->regsel_p->regoff, &data_p[0].value.ui64) 579*4df55fdeSJanie Lu != SUCCESS) 580*4df55fdeSJanie Lu return (EIO); 581*4df55fdeSJanie Lu } else 582*4df55fdeSJanie Lu data_p[0].value.ui64 = 0ull; 583*4df55fdeSJanie Lu 584*4df55fdeSJanie Lu IOSPC_DBG2("iospc_kstat_update: rd event %lx\n", 585*4df55fdeSJanie Lu data_p[0].value.ui64); 586*4df55fdeSJanie Lu 587*4df55fdeSJanie Lu for (counter = 0; counter < grp_p->num_counters; counter++) { 588*4df55fdeSJanie Lu 589*4df55fdeSJanie Lu if (grp_p->access(iospc_p, ksinfop->arg, IOSPC_REG_READ, 590*4df55fdeSJanie Lu grp_p->counters_p[counter].regoff, 591*4df55fdeSJanie Lu &data_p[counter + 1].value.ui64) != SUCCESS) 592*4df55fdeSJanie Lu return (EIO); 593*4df55fdeSJanie Lu 594*4df55fdeSJanie Lu IOSPC_DBG2("cntr%d, off:0x%lx, val:0x%lx\n", counter, 595*4df55fdeSJanie Lu grp_p->counters_p[counter].regoff, 596*4df55fdeSJanie Lu data_p[counter + 1].value.ui64); 597*4df55fdeSJanie Lu } 598*4df55fdeSJanie Lu } 599*4df55fdeSJanie Lu return (SUCCESS); 600*4df55fdeSJanie Lu } 601*4df55fdeSJanie Lu 602*4df55fdeSJanie Lu void 603*4df55fdeSJanie Lu iospc_kstat_fini() 604*4df55fdeSJanie Lu { 605*4df55fdeSJanie Lu iospc_grp_t **grp_pp; 606*4df55fdeSJanie Lu iospc_grp_t *grp_p; 607*4df55fdeSJanie Lu int j; 608*4df55fdeSJanie Lu 609*4df55fdeSJanie Lu IOSPC_DBG2("iospc_kstat_fini called\n"); 610*4df55fdeSJanie Lu 611*4df55fdeSJanie Lu for (j = 0, grp_pp = iospc_leaf_grps; *grp_pp != NULL; j++, grp_pp++) { 612*4df55fdeSJanie Lu grp_p = *grp_pp; 613*4df55fdeSJanie Lu if (grp_p->name_kstats_pp != NULL) { 614*4df55fdeSJanie Lu iospc_delete_name_kstats(grp_p->name_kstats_pp, 615*4df55fdeSJanie Lu grp_p->num_counters); 616*4df55fdeSJanie Lu kmem_free(grp_p->name_kstats_pp, 617*4df55fdeSJanie Lu grp_p->num_counters * sizeof (kstat_t)); 618*4df55fdeSJanie Lu grp_p->name_kstats_pp = NULL; 619*4df55fdeSJanie Lu } 620*4df55fdeSJanie Lu } 621*4df55fdeSJanie Lu } 622*4df55fdeSJanie Lu 623*4df55fdeSJanie Lu static void 624*4df55fdeSJanie Lu iospc_delete_name_kstats(kstat_t **name_kstats_pp, int num_kstats) 625*4df55fdeSJanie Lu { 626*4df55fdeSJanie Lu int i; 627*4df55fdeSJanie Lu 628*4df55fdeSJanie Lu if (name_kstats_pp != NULL) { 629*4df55fdeSJanie Lu for (i = 0; i < num_kstats; i++) { 630*4df55fdeSJanie Lu if (name_kstats_pp[i] != NULL) 631*4df55fdeSJanie Lu kstat_delete(name_kstats_pp[i]); 632*4df55fdeSJanie Lu } 633*4df55fdeSJanie Lu } 634*4df55fdeSJanie Lu } 635*4df55fdeSJanie Lu 636*4df55fdeSJanie Lu void 637*4df55fdeSJanie Lu iospc_kstat_detach(iospc_t *iospc_p) 638*4df55fdeSJanie Lu { 639*4df55fdeSJanie Lu iospc_grp_t **grp_pp; 640*4df55fdeSJanie Lu iospc_grp_t *grp_p; 641*4df55fdeSJanie Lu int i; 642*4df55fdeSJanie Lu 643*4df55fdeSJanie Lu IOSPC_DBG2("iospc_kstat_detach called\n"); 644*4df55fdeSJanie Lu 645*4df55fdeSJanie Lu for (i = 0, grp_pp = iospc_leaf_grps; *grp_pp != NULL; i++, grp_pp++) { 646*4df55fdeSJanie Lu 647*4df55fdeSJanie Lu if (i >= IOSPC_MAX_NUM_GRPS) 648*4df55fdeSJanie Lu return; 649*4df55fdeSJanie Lu 650*4df55fdeSJanie Lu grp_p = *grp_pp; 651*4df55fdeSJanie Lu if (iospc_p->iospc_ksinfo_p[i] != NULL) { 652*4df55fdeSJanie Lu 653*4df55fdeSJanie Lu grp_p->access_fini(iospc_p, iospc_p->iospc_ksinfo_p[i]); 654*4df55fdeSJanie Lu 655*4df55fdeSJanie Lu if (iospc_p->iospc_ksinfo_p[i]->cntr_ksp != NULL) 656*4df55fdeSJanie Lu kstat_delete( 657*4df55fdeSJanie Lu iospc_p->iospc_ksinfo_p[i]->cntr_ksp); 658*4df55fdeSJanie Lu kmem_free(iospc_p->iospc_ksinfo_p[i], 659*4df55fdeSJanie Lu sizeof (iospc_ksinfo_t)); 660*4df55fdeSJanie Lu } 661*4df55fdeSJanie Lu 662*4df55fdeSJanie Lu } 663*4df55fdeSJanie Lu } 664