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