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