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/sunddi.h> 31 #include <sys/sunndi.h> 32 #include <sys/kstat.h> 33 #include <fpc.h> 34 35 /* 36 * CLEAR_PIC is needed by busstat to extract the current event type of a PIC. 37 * There will be an entry for CLEAR_PIC in each fi_kev_mask_t table below, but 38 * they are different from the other entries in that busstat won't show them to 39 * the user. 40 */ 41 #define DEVICE_NAME_LEN 12 42 #define PIC_STR_LEN 12 43 44 /* 45 * Data structure used to build array of event-names and pcr-mask values 46 */ 47 typedef struct fi_kev_mask { 48 char *event_name; 49 uint64_t pcr_mask; 50 } fi_kev_mask_t; 51 52 typedef struct fi_ksinfo { 53 uint32_t pic_num_events; 54 uint32_t pic_leaf_id; 55 uint8_t pic_sel_shift[NUM_MAX_COUNTERS]; 56 kstat_t *pic_name_ksp[NUM_MAX_COUNTERS]; 57 kstat_t *cntr_ksp; 58 fire_perfcnt_t pic_reg_group; 59 } fi_ksinfo_t; 60 61 static fi_ksinfo_t *fi_imu_kstats[NUM_LEAVES]; 62 static fi_ksinfo_t *fi_mmu_kstats[NUM_LEAVES]; 63 static fi_ksinfo_t *fi_tlu_kstats[NUM_LEAVES]; 64 static fi_ksinfo_t *fi_lpu_kstats[NUM_LEAVES]; 65 static fi_ksinfo_t *fi_jbc_kstat; 66 67 static int fpc_create_name_kstat(char *name, fi_ksinfo_t *pp, fi_kev_mask_t *ev, 68 int base, int num_cntrs); 69 static void fpc_delete_name_kstat(fi_ksinfo_t *pp); 70 static kstat_t *fpc_create_cntr_kstat(char *name, int instance, 71 int (*update)(kstat_t *, int), void *ksinfop, int num_pics); 72 static int fpc_cntr_kstat_update(kstat_t *ksp, int rw); 73 static int fpc_dev_kstat(fire_perfcnt_t reg_group, uint8_t num_inst); 74 static kstat_t *fpc_create_picN_kstat(char *mod_name, int pic, 75 int pic_sel_shift, int num_ev, fi_kev_mask_t *ev_array); 76 /* 77 * Below are event lists, which map an event name specified on the commandline 78 * with a value to program the event register with. 79 * 80 * The last entry will be the mask of the entire event field for the PIC and 81 * counter type. 82 */ 83 84 /* 85 * JBC performance events. 86 */ 87 static fi_kev_mask_t 88 fire_jbc_events[] = { 89 {JBC01_S_EVT_NONE, JBC01_EVT_NONE}, 90 {JBC01_S_EVT_CLK, JBC01_EVT_CLK}, 91 {JBC01_S_EVT_IDLE, JBC01_EVT_IDLE}, 92 {JBC01_S_EVT_FIRE, JBC01_EVT_FIRE}, 93 {JBC01_S_EVT_READ_LATENCY, JBC01_EVT_READ_LATENCY}, 94 {JBC01_S_EVT_READ_SAMPLE, JBC01_EVT_READ_SAMPLE}, 95 {JBC01_S_EVT_I2C_PIO, JBC01_EVT_I2C_PIO}, 96 {JBC01_S_EVT_EBUS_PIO, JBC01_EVT_EBUS_PIO}, 97 {JBC01_S_EVT_RINGA_PIO, JBC01_EVT_RINGA_PIO}, 98 {JBC01_S_EVT_RINGB_PIO, JBC01_EVT_RINGB_PIO}, 99 {JBC01_S_EVT_PARTIAL_WR, JBC01_EVT_PARTIAL_WR}, 100 {JBC01_S_EVT_TOTAL_WR, JBC01_EVT_TOTAL_WR}, 101 {JBC01_S_EVT_TOTAL_RD, JBC01_EVT_TOTAL_RD}, 102 {JBC01_S_EVT_AOKOFF, JBC01_EVT_AOKOFF}, 103 {JBC01_S_EVT_DOKOFF, JBC01_EVT_DOKOFF}, 104 {JBC01_S_EVT_DAOKOFF, JBC01_EVT_DAOKOFF}, 105 {JBC01_S_EVT_JBUS_COH_XACT, JBC01_EVT_JBUS_COH_XACT}, 106 {JBC01_S_EVT_FIRE_COH_XACT, JBC01_EVT_FIRE_COH_XACT}, 107 {JBC01_S_EVT_JBUS_NCOH_XACT, JBC01_EVT_JBUS_NCOH_XACT}, 108 {JBC01_S_EVT_FGN_IO_HIT, JBC01_EVT_FGN_IO_HIT}, 109 {JBC01_S_EVT_FIRE_WBS, JBC01_EVT_FIRE_WBS}, 110 {JBC01_S_EVT_PCIEA_PIO_WR, JBC01_EVT_PCIEA_PIO_WR}, 111 {JBC01_S_EVT_PCIEA_PIO_RD, JBC01_EVT_PCIEA_PIO_RD}, 112 {JBC01_S_EVT_PCIEB_PIO_WR, JBC01_EVT_PCIEB_PIO_WR}, 113 {JBC01_S_EVT_PCIEB_PIO_RD, JBC01_EVT_PCIEB_PIO_RD}, 114 {COMMON_S_CLEAR_PIC, JBC01_EVT_MASK} 115 }; 116 117 /* 118 * IMU performance events 119 */ 120 static fi_kev_mask_t 121 fire_imu_events[] = { 122 {IMU01_S_EVT_NONE, IMU01_EVT_NONE}, 123 {IMU01_S_EVT_CLK, IMU01_EVT_CLK}, 124 {IMU01_S_EVT_MONDO, IMU01_EVT_MONDO}, 125 {IMU01_S_EVT_MSI, IMU01_EVT_MSI}, 126 {IMU01_S_EVT_MONDO_NAKS, IMU01_EVT_MONDO_NAKS}, 127 {IMU01_S_EVT_EQ_WR, IMU01_EVT_EQ_WR}, 128 {IMU01_S_EVT_EQ_MONDO, IMU01_EVT_EQ_MONDO}, 129 {COMMON_S_CLEAR_PIC, IMU01_EVT_MASK} 130 }; 131 132 /* 133 * MMU performance events 134 */ 135 static fi_kev_mask_t 136 fire_mmu_events[] = { 137 {MMU01_S_EVT_NONE, MMU01_EVT_NONE}, 138 {MMU01_S_EVT_CLK, MMU01_EVT_CLK}, 139 {MMU01_S_EVT_TRANS, MMU01_EVT_TRANSL}, 140 {MMU01_S_EVT_STALL, MMU01_EVT_STALL}, 141 {MMU01_S_EVT_TRANSL_MISS, MMU01_EVT_TRANSL_MISS}, 142 {MMU01_S_EVT_TBLWLK_STALL, MMU01_EVT_TBLWLK_STALL}, 143 {MMU01_S_EVT_BYPASS_TRANSL, MMU01_EVT_BYPASS_TRANSL}, 144 {MMU01_S_EVT_TRANSL_TRANSL, MMU01_EVT_TRANSL_TRANSL}, 145 {MMU01_S_EVT_FLOW_CNTL_STALL, MMU01_EVT_FLOW_CNTL_STALL}, 146 {MMU01_S_EVT_FLUSH_CACHE_ENT, MMU01_EVT_FLUSH_CACHE_ENT}, 147 {COMMON_S_CLEAR_PIC, MMU01_EVT_MASK} 148 }; 149 150 /* 151 * TLU performance events for counters 0 and 1 152 */ 153 static fi_kev_mask_t 154 fire_tlu_events[] = { 155 {TLU01_S_EVT_NONE, TLU01_EVT_NONE}, 156 {TLU01_S_EVT_CLK, TLU01_EVT_CLK}, 157 {TLU01_S_EVT_COMPL, TLU01_EVT_COMPL}, 158 {TLU01_S_EVT_XMT_POST_CR_UNAV, TLU01_EVT_XMT_POST_CR_UNAV}, 159 {TLU01_S_EVT_XMT_NPOST_CR_UNAV, TLU01_EVT_XMT_NPOST_CR_UNAV}, 160 {TLU01_S_EVT_XMT_CMPL_CR_UNAV, TLU01_EVT_XMT_CMPL_CR_UNAV}, 161 {TLU01_S_EVT_XMT_ANY_CR_UNAV, TLU01_EVT_XMT_ANY_CR_UNAV}, 162 {TLU01_S_EVT_RETRY_CR_UNAV, TLU01_EVT_RETRY_CR_UNAV}, 163 {TLU01_S_EVT_MEMRD_PKT_RCVD, TLU01_EVT_MEMRD_PKT_RCVD}, 164 {TLU01_S_EVT_MEMWR_PKT_RCVD, TLU01_EVT_MEMWR_PKT_RCVD}, 165 {TLU01_S_EVT_RCV_CR_THRESH, TLU01_EVT_RCV_CR_THRESH}, 166 {TLU01_S_EVT_RCV_PST_HDR_CR_EXH, TLU01_EVT_RCV_PST_HDR_CR_EXH}, 167 {TLU01_S_EVT_RCV_PST_DA_CR_MPS, TLU01_EVT_RCV_PST_DA_CR_MPS}, 168 {TLU01_S_EVT_RCV_NPST_HDR_CR_EXH, TLU01_EVT_RCV_NPST_HDR_CR_EXH}, 169 {TLU01_S_EVT_RCVR_L0S, TLU01_EVT_RCVR_L0S}, 170 {TLU01_S_EVT_RCVR_L0S_TRANS, TLU01_EVT_RCVR_L0S_TRANS}, 171 {TLU01_S_EVT_XMTR_L0S, TLU01_EVT_XMTR_L0S}, 172 {TLU01_S_EVT_XMTR_L0S_TRANS, TLU01_EVT_XMTR_L0S_TRANS}, 173 {TLU01_S_EVT_RCVR_ERR, TLU01_EVT_RCVR_ERR}, 174 {TLU01_S_EVT_BAD_TLP, TLU01_EVT_BAD_TLP}, 175 {TLU01_S_EVT_BAD_DLLP, TLU01_EVT_BAD_DLLP}, 176 {TLU01_S_EVT_REPLAY_ROLLOVER, TLU01_EVT_REPLAY_ROLLOVER}, 177 {TLU01_S_EVT_REPLAY_TMO, TLU01_EVT_REPLAY_TMO}, 178 {COMMON_S_CLEAR_PIC, TLU01_EVT_MASK} 179 }; 180 181 /* 182 * TLU performance events for counter 2 183 */ 184 static fi_kev_mask_t 185 fire_tlu2_events[] = { 186 {TLU2_S_EVT_NONE, TLU2_EVT_NONE}, 187 {TLU2_S_EVT_NON_POST_COMPL_TIME, TLU2_EVT_NON_POST_COMPL_TIME}, 188 {TLU2_S_EVT_XMT_DATA_WORD, TLU2_EVT_XMT_DATA_WORD}, 189 {TLU2_S_EVT_RCVD_DATA_WORD, TLU2_EVT_RCVD_DATA_WORD}, 190 {COMMON_S_CLEAR_PIC, TLU2_EVT_MASK} 191 }; 192 193 /* 194 * LPU performance events 195 */ 196 static fi_kev_mask_t 197 fire_lpu_events[] = { 198 {LPU12_S_EVT_RESET, LPU12_EVT_RESET}, 199 {LPU12_S_EVT_TLP_RCVD, LPU12_EVT_TLP_RCVD}, 200 {LPU12_S_EVT_DLLP_RCVD, LPU12_EVT_DLLP_RCVD}, 201 {LPU12_S_EVT_ACK_DLLP_RCVD, LPU12_EVT_ACK_DLLP_RCVD}, 202 {LPU12_S_EVT_NAK_DLLP_RCVD, LPU12_EVT_NAK_DLLP_RCVD}, 203 {LPU12_S_EVT_RETRY_START, LPU12_EVT_RETRY_START}, 204 {LPU12_S_EVT_REPLAY_TMO, LPU12_EVT_REPLAY_TMO}, 205 {LPU12_S_EVT_ACK_NAK_LAT_TMO, LPU12_EVT_ACK_NAK_LAT_TMO}, 206 {LPU12_S_EVT_BAD_DLLP, LPU12_EVT_BAD_DLLP}, 207 {LPU12_S_EVT_BAD_TLP, LPU12_EVT_BAD_TLP}, 208 {LPU12_S_EVT_NAK_DLLP_SENT, LPU12_EVT_NAK_DLLP_SENT}, 209 {LPU12_S_EVT_ACK_DLLP_SENT, LPU12_EVT_ACK_DLLP_SENT}, 210 {LPU12_S_EVT_RCVR_ERROR, LPU12_EVT_RCVR_ERROR}, 211 {LPU12_S_EVT_LTSSM_RECOV_ENTRY, LPU12_EVT_LTSSM_RECOV_ENTRY}, 212 {LPU12_S_EVT_REPLAY_IN_PROG, LPU12_EVT_REPLAY_IN_PROG}, 213 {LPU12_S_EVT_TLP_XMT_IN_PROG, LPU12_EVT_TLP_XMT_IN_PROG}, 214 {LPU12_S_EVT_CLK_CYC, LPU12_EVT_CLK_CYC}, 215 {LPU12_S_EVT_TLP_DLLP_XMT_PROG, LPU12_EVT_TLP_DLLP_XMT_PROG}, 216 {LPU12_S_EVT_TLP_DLLP_RCV_PROG, LPU12_EVT_TLP_DLLP_RCV_PROG}, 217 {COMMON_S_CLEAR_PIC, LPU12_EVT_MASK} 218 }; 219 220 int 221 fpc_kstat_init(dev_info_t *dip) 222 { 223 fire_perfcnt_t i; 224 int avail; 225 uint8_t num_inst = 0; 226 227 if (fpc_perfcnt_module_init(dip, &avail) != DDI_SUCCESS) 228 return (DDI_FAILURE); 229 230 if (avail & PCIE_A_REGS_AVAIL) 231 num_inst++; 232 if (avail & PCIE_B_REGS_AVAIL) 233 num_inst++; 234 235 for (i = jbc; i < MAX_REG_TYPES; i++) { 236 if (i == jbc) { 237 if (avail & JBUS_REGS_AVAIL) { 238 if (fpc_dev_kstat(i, 1) != SUCCESS) 239 return (DDI_FAILURE); 240 } 241 } else { 242 if (!num_inst) 243 break; 244 if (fpc_dev_kstat(i, num_inst) != SUCCESS) 245 return (DDI_FAILURE); 246 } 247 } 248 249 return (DDI_SUCCESS); 250 } 251 252 static int 253 fpc_dev_kstat(fire_perfcnt_t reg_group, uint8_t num_inst) 254 { 255 int i, base_cntrid, num_cntrs; 256 uint32_t num_events, num_events2; 257 char dev_name[DEVICE_NAME_LEN]; 258 fi_ksinfo_t *ksinfop; 259 fi_kev_mask_t *fire_events, *fire_events2; 260 261 switch (reg_group) { 262 case imu: 263 (void) strncpy(dev_name, "pciex_imu", sizeof (dev_name)); 264 num_events = sizeof (fire_imu_events) / sizeof (fi_kev_mask_t); 265 fire_events = fire_imu_events; 266 num_cntrs = NUM_IMU_COUNTERS; 267 break; 268 case mmu: 269 (void) strncpy(dev_name, "pciex_mmu", sizeof (dev_name)); 270 num_events = sizeof (fire_mmu_events) / sizeof (fi_kev_mask_t); 271 fire_events = fire_mmu_events; 272 num_cntrs = NUM_MMU_COUNTERS; 273 break; 274 case lpu: 275 (void) strncpy(dev_name, "pciex_lpu", sizeof (dev_name)); 276 num_events = sizeof (fire_lpu_events) / sizeof (fi_kev_mask_t); 277 fire_events = fire_lpu_events; 278 num_cntrs = NUM_LPU_COUNTERS; 279 break; 280 case tlu: 281 (void) strncpy(dev_name, "pciex_tlu", sizeof (dev_name)); 282 num_events = sizeof (fire_tlu_events) / sizeof (fi_kev_mask_t); 283 num_events2 = sizeof (fire_tlu2_events) / 284 sizeof (fi_kev_mask_t); 285 fire_events = fire_tlu_events; 286 fire_events2 = fire_tlu2_events; 287 num_cntrs = NUM_TLU_COUNTERS; 288 break; 289 case jbc: 290 (void) strncpy(dev_name, "jbc", sizeof (dev_name)); 291 num_events = sizeof (fire_jbc_events) / sizeof (fi_kev_mask_t); 292 fire_events = fire_jbc_events; 293 num_cntrs = NUM_JBC_COUNTERS; 294 break; 295 default: 296 return (FAILURE); 297 } 298 299 for (i = 0; i < num_inst; i++) { 300 ksinfop = (fi_ksinfo_t *)kmem_zalloc(sizeof (fi_ksinfo_t), 301 KM_SLEEP); 302 303 ksinfop->pic_num_events = num_events; 304 ksinfop->pic_reg_group = reg_group; 305 ksinfop->pic_leaf_id = i; 306 ksinfop->pic_sel_shift[0] = PIC0_EVT_SEL_SHIFT; 307 308 if (reg_group == lpu) 309 ksinfop->pic_sel_shift[1] = PIC2_EVT_SEL_SHIFT; 310 else 311 ksinfop->pic_sel_shift[1] = PIC1_EVT_SEL_SHIFT; 312 313 /* 314 * All error cleanup (deleting kstats and freeing memory) is 315 * done in fire_kstat_fini. So we need to save the ksinfop 316 * pointer before any possible error exit so fire_kstat_fini 317 * can find it. 318 */ 319 if (reg_group == imu) 320 fi_imu_kstats[i] = ksinfop; 321 else if (reg_group == mmu) 322 fi_mmu_kstats[i] = ksinfop; 323 else if (reg_group == lpu) 324 fi_lpu_kstats[i] = ksinfop; 325 else if (reg_group == tlu) 326 fi_tlu_kstats[i] = ksinfop; 327 else if (reg_group == jbc) 328 fi_jbc_kstat = ksinfop; 329 330 /* Create basic pic event-type pair (only once) */ 331 if (i == 0) { 332 base_cntrid = 0; 333 334 /* The extra counter for TLU is handled separately */ 335 if (reg_group == tlu) 336 num_cntrs--; 337 338 if (fpc_create_name_kstat(dev_name, ksinfop, 339 fire_events, base_cntrid, num_cntrs) != SUCCESS) 340 goto err; 341 342 /* 343 * extra counter for TLU. The events associated with 344 * this third counter are different from the events 345 * for the first and second counters. 346 */ 347 if (reg_group == tlu) { 348 ksinfop->pic_sel_shift[2] = PIC2_EVT_SEL_SHIFT; 349 base_cntrid += num_cntrs; 350 num_cntrs = 1; 351 ksinfop->pic_num_events = num_events2; 352 if (fpc_create_name_kstat(dev_name, ksinfop, 353 fire_events2, base_cntrid, num_cntrs) 354 != SUCCESS) 355 goto err; 356 357 num_cntrs = NUM_TLU_COUNTERS; 358 } 359 360 } 361 362 /* create counter kstats */ 363 ksinfop->cntr_ksp = fpc_create_cntr_kstat(dev_name, i, 364 fpc_cntr_kstat_update, ksinfop, num_cntrs); 365 if (ksinfop->cntr_ksp == NULL) 366 goto err; 367 368 } 369 return (SUCCESS); 370 err: 371 return (FAILURE); 372 373 } 374 375 static int 376 fpc_create_name_kstat(char *name, fi_ksinfo_t *pp, fi_kev_mask_t *ev, 377 int base, int num_cntrs) 378 { 379 int i; 380 381 #ifdef DEBUG 382 FPC_DBG2("fpc_create_name_kstat: name: %s\n", name); 383 #endif 384 385 for (i = base; i < (base + num_cntrs); i++) { 386 pp->pic_name_ksp[i] = fpc_create_picN_kstat(name, i, 387 pp->pic_sel_shift[i], pp->pic_num_events, ev); 388 389 if (pp->pic_name_ksp[i] == NULL) 390 return (FAILURE); 391 } 392 return (SUCCESS); 393 } 394 395 /* 396 * Create the picN kstat. Returns a pointer to the 397 * kstat which the driver must store to allow it 398 * to be deleted when necessary. 399 */ 400 static kstat_t * 401 fpc_create_picN_kstat(char *mod_name, int pic, int pic_sel_shift, int num_ev, 402 fi_kev_mask_t *ev_array) 403 { 404 int event; 405 char pic_name[PIC_STR_LEN]; 406 kstat_t *picN_ksp = NULL; 407 struct kstat_named *pic_named_data; 408 409 (void) snprintf(pic_name, sizeof (pic_name), "pic%d", pic); 410 if ((picN_ksp = kstat_create(mod_name, 0, pic_name, 411 "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) { 412 cmn_err(CE_WARN, "%s %s : kstat create failed", 413 mod_name, pic_name); 414 return (NULL); 415 } 416 417 pic_named_data = (struct kstat_named *)picN_ksp->ks_data; 418 419 /* 420 * Fill up data section of the kstat 421 * Write event names and their associated pcr masks. 422 * num_ev - 1 is because CLEAR_PIC is added separately. 423 */ 424 for (event = 0; event < num_ev - 1; event++) { 425 pic_named_data[event].value.ui64 = 426 (ev_array[event].pcr_mask << pic_sel_shift); 427 428 kstat_named_init(&pic_named_data[event], 429 ev_array[event].event_name, KSTAT_DATA_UINT64); 430 } 431 432 /* 433 * add the clear_pic entry 434 */ 435 pic_named_data[event].value.ui64 = 436 (uint64_t)~(ev_array[event].pcr_mask << pic_sel_shift); 437 438 kstat_named_init(&pic_named_data[event], ev_array[event].event_name, 439 KSTAT_DATA_UINT64); 440 441 kstat_install(picN_ksp); 442 443 #ifdef DEBUG 444 FPC_DBG2("fpc_create_picN_kstat: name %s, pic %d, num_ev %d, " 445 "pic_sel_shift %d\n", mod_name, pic, num_ev, pic_sel_shift); 446 #endif 447 448 return (picN_ksp); 449 } 450 451 /* 452 * Create the "counters" kstat. 453 */ 454 static kstat_t * 455 fpc_create_cntr_kstat(char *name, int instance, int (*update)(kstat_t *, int), 456 void *ksinfop, int num_pics) 457 { 458 int i; 459 char pic_str[PIC_STR_LEN]; 460 struct kstat *counters_ksp; 461 struct kstat_named *counters_named_data; 462 463 #ifdef DEBUG 464 FPC_DBG1("fpc_create_cntr_kstat: name: %s instance: %d\n", 465 name, instance); 466 #endif 467 468 /* 469 * Size of kstat is num_pics + 1. extra one for pcr. 470 */ 471 if ((counters_ksp = kstat_create(name, instance, "counters", "bus", 472 KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) { 473 cmn_err(CE_WARN, "kstat_create for %s%d failed", 474 name, instance); 475 return (NULL); 476 } 477 478 counters_named_data = (struct kstat_named *)(counters_ksp->ks_data); 479 kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64); 480 481 for (i = 0; i < num_pics; i++) { 482 (void) snprintf(pic_str, sizeof (pic_str), "pic%d", i); 483 484 kstat_named_init(&counters_named_data[i+1], pic_str, 485 KSTAT_DATA_UINT64); 486 } 487 488 /* 489 * Store the reg type and other info. in the kstat's private field 490 * so that they are available to the update function. 491 */ 492 counters_ksp->ks_private = (void *)ksinfop; 493 counters_ksp->ks_update = update; 494 495 kstat_install(counters_ksp); 496 497 return (counters_ksp); 498 } 499 500 /* 501 * kstat update function. Handles reads/writes 502 * from/to kstat. 503 */ 504 static int 505 fpc_cntr_kstat_update(kstat_t *ksp, int rw) 506 { 507 struct kstat_named *data_p; 508 fi_ksinfo_t *ksinfop = ksp->ks_private; 509 uint64_t counters[NUM_MAX_COUNTERS]; 510 uint64_t event; 511 512 data_p = (struct kstat_named *)ksp->ks_data; 513 514 if (rw == KSTAT_WRITE) { 515 #ifdef DEBUG 516 FPC_DBG2("fpc_cntr_kstat_update: wr %ld\n", 517 data_p[0].value.ui64); 518 #endif 519 520 if (fpc_perfcnt_program(ksinfop->pic_leaf_id, 521 ksinfop->pic_reg_group, data_p[0].value.ui64) != SUCCESS) 522 return (EIO); 523 } else { 524 counters[2] = 0; 525 if (fpc_perfcnt_read(ksinfop->pic_leaf_id, 526 ksinfop->pic_reg_group, &event, counters) != SUCCESS) 527 return (EIO); 528 529 data_p[0].value.ui64 = event; 530 data_p[1].value.ui64 = counters[0]; 531 data_p[2].value.ui64 = counters[1]; 532 533 if (ksinfop->pic_reg_group == tlu) { 534 data_p[3].value.ui64 = counters[2]; 535 } 536 #ifdef DEBUG 537 FPC_DBG2("fpc_cntr_kstat_update: rd event %ld, cntr0" 538 " %ld, cntr1 %ld, cntr2 %ld\n", data_p[0].value.ui64, 539 counters[0], counters[1], counters[2]); 540 #endif 541 } 542 return (0); 543 } 544 545 void 546 fpc_kstat_fini(dev_info_t *dip) 547 { 548 int i; 549 550 #ifdef DEBUG 551 FPC_DBG1("fpc_kstat_fini called\n"); 552 #endif 553 554 for (i = 0; i < NUM_LEAVES; i++) { 555 /* IMU */ 556 if (fi_imu_kstats[i] != NULL) { 557 fpc_delete_name_kstat(fi_imu_kstats[i]); 558 if (fi_imu_kstats[i]->cntr_ksp != NULL) 559 kstat_delete(fi_imu_kstats[i]->cntr_ksp); 560 kmem_free(fi_imu_kstats[i], sizeof (fi_ksinfo_t)); 561 fi_imu_kstats[i] = NULL; 562 } 563 564 /* MMU */ 565 if (fi_mmu_kstats[i] != NULL) { 566 fpc_delete_name_kstat(fi_mmu_kstats[i]); 567 if (fi_mmu_kstats[i]->cntr_ksp != NULL) 568 kstat_delete(fi_mmu_kstats[i]->cntr_ksp); 569 kmem_free(fi_mmu_kstats[i], sizeof (fi_ksinfo_t)); 570 fi_mmu_kstats[i] = NULL; 571 } 572 573 /* LPU */ 574 if (fi_lpu_kstats[i] != NULL) { 575 fpc_delete_name_kstat(fi_lpu_kstats[i]); 576 if (fi_lpu_kstats[i]->cntr_ksp != NULL) 577 kstat_delete(fi_lpu_kstats[i]->cntr_ksp); 578 kmem_free(fi_lpu_kstats[i], sizeof (fi_ksinfo_t)); 579 fi_lpu_kstats[i] = NULL; 580 } 581 582 /* TLU */ 583 if (fi_tlu_kstats[i] != NULL) { 584 fpc_delete_name_kstat(fi_tlu_kstats[i]); 585 if (fi_tlu_kstats[i]->cntr_ksp != NULL) 586 kstat_delete(fi_tlu_kstats[i]->cntr_ksp); 587 kmem_free(fi_tlu_kstats[i], sizeof (fi_ksinfo_t)); 588 fi_tlu_kstats[i] = NULL; 589 } 590 } 591 592 /* JBC */ 593 if (fi_jbc_kstat != NULL) { 594 fpc_delete_name_kstat(fi_jbc_kstat); 595 if (fi_jbc_kstat->cntr_ksp != NULL) 596 kstat_delete(fi_jbc_kstat->cntr_ksp); 597 kmem_free(fi_jbc_kstat, sizeof (fi_ksinfo_t)); 598 fi_jbc_kstat = NULL; 599 } 600 601 (void) fpc_perfcnt_module_fini(dip); 602 } 603 604 static void 605 fpc_delete_name_kstat(fi_ksinfo_t *pp) 606 { 607 int i; 608 609 if (pp != NULL) { 610 for (i = 0; i < NUM_MAX_COUNTERS; i++) { 611 if (pp->pic_name_ksp[i] != NULL) 612 kstat_delete(pp->pic_name_ksp[i]); 613 } 614 } 615 } 616