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