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