1110e73f9Sschwartz /* 2110e73f9Sschwartz * CDDL HEADER START 3110e73f9Sschwartz * 4110e73f9Sschwartz * The contents of this file are subject to the terms of the 5110e73f9Sschwartz * Common Development and Distribution License (the "License"). 6110e73f9Sschwartz * You may not use this file except in compliance with the License. 7110e73f9Sschwartz * 8110e73f9Sschwartz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9110e73f9Sschwartz * or http://www.opensolaris.org/os/licensing. 10110e73f9Sschwartz * See the License for the specific language governing permissions 11110e73f9Sschwartz * and limitations under the License. 12110e73f9Sschwartz * 13110e73f9Sschwartz * When distributing Covered Code, include this CDDL HEADER in each 14110e73f9Sschwartz * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15110e73f9Sschwartz * If applicable, add the following below this CDDL HEADER, with the 16110e73f9Sschwartz * fields enclosed by brackets "[]" replaced with your own identifying 17110e73f9Sschwartz * information: Portions Copyright [yyyy] [name of copyright owner] 18110e73f9Sschwartz * 19110e73f9Sschwartz * CDDL HEADER END 20110e73f9Sschwartz */ 21110e73f9Sschwartz 22110e73f9Sschwartz /* 23*ae53df47Skd93003 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24110e73f9Sschwartz * Use is subject to license terms. 25110e73f9Sschwartz */ 26110e73f9Sschwartz 27110e73f9Sschwartz #pragma ident "%Z%%M% %I% %E% SMI" 28110e73f9Sschwartz 29110e73f9Sschwartz #include <sys/types.h> 30110e73f9Sschwartz #include <sys/sunddi.h> 31110e73f9Sschwartz #include <sys/sunndi.h> 32110e73f9Sschwartz #include <sys/kstat.h> 33110e73f9Sschwartz #include <fpc.h> 34110e73f9Sschwartz 35110e73f9Sschwartz /* 36110e73f9Sschwartz * CLEAR_PIC is needed by busstat to extract the current event type of a PIC. 37110e73f9Sschwartz * There will be an entry for CLEAR_PIC in each fi_kev_mask_t table below, but 38110e73f9Sschwartz * they are different from the other entries in that busstat won't show them to 39110e73f9Sschwartz * the user. 40110e73f9Sschwartz */ 41*ae53df47Skd93003 #define DEVICE_NAME_LEN 4 42110e73f9Sschwartz #define PIC_STR_LEN 12 43110e73f9Sschwartz 44110e73f9Sschwartz /* 45110e73f9Sschwartz * Data structure used to build array of event-names and pcr-mask values 46110e73f9Sschwartz */ 47110e73f9Sschwartz typedef struct fi_kev_mask { 48110e73f9Sschwartz char *event_name; 49110e73f9Sschwartz uint64_t pcr_mask; 50110e73f9Sschwartz } fi_kev_mask_t; 51110e73f9Sschwartz 52110e73f9Sschwartz typedef struct fi_ksinfo { 53110e73f9Sschwartz uint32_t pic_num_events; 54110e73f9Sschwartz uint32_t pic_leaf_id; 55110e73f9Sschwartz uint8_t pic_sel_shift[NUM_MAX_COUNTERS]; 56110e73f9Sschwartz kstat_t *pic_name_ksp[NUM_MAX_COUNTERS]; 57110e73f9Sschwartz kstat_t *cntr_ksp; 58110e73f9Sschwartz fire_perfcnt_t pic_reg_group; 59110e73f9Sschwartz } fi_ksinfo_t; 60110e73f9Sschwartz 61110e73f9Sschwartz static fi_ksinfo_t *fi_imu_kstats[NUM_LEAVES]; 62110e73f9Sschwartz static fi_ksinfo_t *fi_mmu_kstats[NUM_LEAVES]; 63110e73f9Sschwartz static fi_ksinfo_t *fi_tlu_kstats[NUM_LEAVES]; 64110e73f9Sschwartz static fi_ksinfo_t *fi_lpu_kstats[NUM_LEAVES]; 65110e73f9Sschwartz static fi_ksinfo_t *fi_jbc_kstat; 66110e73f9Sschwartz 67110e73f9Sschwartz static int fpc_create_name_kstat(char *name, fi_ksinfo_t *pp, fi_kev_mask_t *ev, 68110e73f9Sschwartz int base, int num_cntrs); 69110e73f9Sschwartz static void fpc_delete_name_kstat(fi_ksinfo_t *pp); 70110e73f9Sschwartz static kstat_t *fpc_create_cntr_kstat(char *name, int instance, 71110e73f9Sschwartz int (*update)(kstat_t *, int), void *ksinfop, int num_pics); 72110e73f9Sschwartz static int fpc_cntr_kstat_update(kstat_t *ksp, int rw); 73110e73f9Sschwartz static int fpc_dev_kstat(fire_perfcnt_t reg_group, uint8_t num_inst); 74110e73f9Sschwartz static kstat_t *fpc_create_picN_kstat(char *mod_name, int pic, 75110e73f9Sschwartz int pic_sel_shift, int num_ev, fi_kev_mask_t *ev_array); 76110e73f9Sschwartz /* 77110e73f9Sschwartz * Below are event lists, which map an event name specified on the commandline 78110e73f9Sschwartz * with a value to program the event register with. 79110e73f9Sschwartz * 80110e73f9Sschwartz * The last entry will be the mask of the entire event field for the PIC and 81110e73f9Sschwartz * counter type. 82110e73f9Sschwartz */ 83110e73f9Sschwartz 84110e73f9Sschwartz /* 85110e73f9Sschwartz * JBC performance events. 86110e73f9Sschwartz */ 87110e73f9Sschwartz static fi_kev_mask_t 88110e73f9Sschwartz fire_jbc_events[] = { 89110e73f9Sschwartz {JBC01_S_EVT_NONE, JBC01_EVT_NONE}, 90110e73f9Sschwartz {JBC01_S_EVT_CLK, JBC01_EVT_CLK}, 91110e73f9Sschwartz {JBC01_S_EVT_IDLE, JBC01_EVT_IDLE}, 92110e73f9Sschwartz {JBC01_S_EVT_FIRE, JBC01_EVT_FIRE}, 93110e73f9Sschwartz {JBC01_S_EVT_READ_LATENCY, JBC01_EVT_READ_LATENCY}, 94110e73f9Sschwartz {JBC01_S_EVT_READ_SAMPLE, JBC01_EVT_READ_SAMPLE}, 95110e73f9Sschwartz {JBC01_S_EVT_I2C_PIO, JBC01_EVT_I2C_PIO}, 96110e73f9Sschwartz {JBC01_S_EVT_EBUS_PIO, JBC01_EVT_EBUS_PIO}, 97110e73f9Sschwartz {JBC01_S_EVT_RINGA_PIO, JBC01_EVT_RINGA_PIO}, 98110e73f9Sschwartz {JBC01_S_EVT_RINGB_PIO, JBC01_EVT_RINGB_PIO}, 99110e73f9Sschwartz {JBC01_S_EVT_PARTIAL_WR, JBC01_EVT_PARTIAL_WR}, 100110e73f9Sschwartz {JBC01_S_EVT_TOTAL_WR, JBC01_EVT_TOTAL_WR}, 101110e73f9Sschwartz {JBC01_S_EVT_TOTAL_RD, JBC01_EVT_TOTAL_RD}, 102110e73f9Sschwartz {JBC01_S_EVT_AOKOFF, JBC01_EVT_AOKOFF}, 103110e73f9Sschwartz {JBC01_S_EVT_DOKOFF, JBC01_EVT_DOKOFF}, 104110e73f9Sschwartz {JBC01_S_EVT_DAOKOFF, JBC01_EVT_DAOKOFF}, 105110e73f9Sschwartz {JBC01_S_EVT_JBUS_COH_XACT, JBC01_EVT_JBUS_COH_XACT}, 106110e73f9Sschwartz {JBC01_S_EVT_FIRE_COH_XACT, JBC01_EVT_FIRE_COH_XACT}, 107110e73f9Sschwartz {JBC01_S_EVT_JBUS_NCOH_XACT, JBC01_EVT_JBUS_NCOH_XACT}, 108110e73f9Sschwartz {JBC01_S_EVT_FGN_IO_HIT, JBC01_EVT_FGN_IO_HIT}, 109110e73f9Sschwartz {JBC01_S_EVT_FIRE_WBS, JBC01_EVT_FIRE_WBS}, 110110e73f9Sschwartz {JBC01_S_EVT_PCIEA_PIO_WR, JBC01_EVT_PCIEA_PIO_WR}, 111110e73f9Sschwartz {JBC01_S_EVT_PCIEA_PIO_RD, JBC01_EVT_PCIEA_PIO_RD}, 112110e73f9Sschwartz {JBC01_S_EVT_PCIEB_PIO_WR, JBC01_EVT_PCIEB_PIO_WR}, 113110e73f9Sschwartz {JBC01_S_EVT_PCIEB_PIO_RD, JBC01_EVT_PCIEB_PIO_RD}, 114110e73f9Sschwartz {COMMON_S_CLEAR_PIC, JBC01_EVT_MASK} 115110e73f9Sschwartz }; 116110e73f9Sschwartz 117110e73f9Sschwartz /* 118110e73f9Sschwartz * IMU performance events 119110e73f9Sschwartz */ 120110e73f9Sschwartz static fi_kev_mask_t 121110e73f9Sschwartz fire_imu_events[] = { 122110e73f9Sschwartz {IMU01_S_EVT_NONE, IMU01_EVT_NONE}, 123110e73f9Sschwartz {IMU01_S_EVT_CLK, IMU01_EVT_CLK}, 124110e73f9Sschwartz {IMU01_S_EVT_MONDO, IMU01_EVT_MONDO}, 125110e73f9Sschwartz {IMU01_S_EVT_MSI, IMU01_EVT_MSI}, 126110e73f9Sschwartz {IMU01_S_EVT_MONDO_NAKS, IMU01_EVT_MONDO_NAKS}, 127110e73f9Sschwartz {IMU01_S_EVT_EQ_WR, IMU01_EVT_EQ_WR}, 128110e73f9Sschwartz {IMU01_S_EVT_EQ_MONDO, IMU01_EVT_EQ_MONDO}, 129110e73f9Sschwartz {COMMON_S_CLEAR_PIC, IMU01_EVT_MASK} 130110e73f9Sschwartz }; 131110e73f9Sschwartz 132110e73f9Sschwartz /* 133110e73f9Sschwartz * MMU performance events 134110e73f9Sschwartz */ 135110e73f9Sschwartz static fi_kev_mask_t 136110e73f9Sschwartz fire_mmu_events[] = { 137110e73f9Sschwartz {MMU01_S_EVT_NONE, MMU01_EVT_NONE}, 138110e73f9Sschwartz {MMU01_S_EVT_CLK, MMU01_EVT_CLK}, 139110e73f9Sschwartz {MMU01_S_EVT_TRANS, MMU01_EVT_TRANSL}, 140110e73f9Sschwartz {MMU01_S_EVT_STALL, MMU01_EVT_STALL}, 141110e73f9Sschwartz {MMU01_S_EVT_TRANSL_MISS, MMU01_EVT_TRANSL_MISS}, 142110e73f9Sschwartz {MMU01_S_EVT_TBLWLK_STALL, MMU01_EVT_TBLWLK_STALL}, 143110e73f9Sschwartz {MMU01_S_EVT_BYPASS_TRANSL, MMU01_EVT_BYPASS_TRANSL}, 144110e73f9Sschwartz {MMU01_S_EVT_TRANSL_TRANSL, MMU01_EVT_TRANSL_TRANSL}, 145110e73f9Sschwartz {MMU01_S_EVT_FLOW_CNTL_STALL, MMU01_EVT_FLOW_CNTL_STALL}, 146110e73f9Sschwartz {MMU01_S_EVT_FLUSH_CACHE_ENT, MMU01_EVT_FLUSH_CACHE_ENT}, 147110e73f9Sschwartz {COMMON_S_CLEAR_PIC, MMU01_EVT_MASK} 148110e73f9Sschwartz }; 149110e73f9Sschwartz 150110e73f9Sschwartz /* 151110e73f9Sschwartz * TLU performance events for counters 0 and 1 152110e73f9Sschwartz */ 153110e73f9Sschwartz static fi_kev_mask_t 154110e73f9Sschwartz fire_tlu_events[] = { 155110e73f9Sschwartz {TLU01_S_EVT_NONE, TLU01_EVT_NONE}, 156110e73f9Sschwartz {TLU01_S_EVT_CLK, TLU01_EVT_CLK}, 157110e73f9Sschwartz {TLU01_S_EVT_COMPL, TLU01_EVT_COMPL}, 158110e73f9Sschwartz {TLU01_S_EVT_XMT_POST_CR_UNAV, TLU01_EVT_XMT_POST_CR_UNAV}, 159110e73f9Sschwartz {TLU01_S_EVT_XMT_NPOST_CR_UNAV, TLU01_EVT_XMT_NPOST_CR_UNAV}, 160110e73f9Sschwartz {TLU01_S_EVT_XMT_CMPL_CR_UNAV, TLU01_EVT_XMT_CMPL_CR_UNAV}, 161110e73f9Sschwartz {TLU01_S_EVT_XMT_ANY_CR_UNAV, TLU01_EVT_XMT_ANY_CR_UNAV}, 162110e73f9Sschwartz {TLU01_S_EVT_RETRY_CR_UNAV, TLU01_EVT_RETRY_CR_UNAV}, 163110e73f9Sschwartz {TLU01_S_EVT_MEMRD_PKT_RCVD, TLU01_EVT_MEMRD_PKT_RCVD}, 164110e73f9Sschwartz {TLU01_S_EVT_MEMWR_PKT_RCVD, TLU01_EVT_MEMWR_PKT_RCVD}, 165110e73f9Sschwartz {TLU01_S_EVT_RCV_CR_THRESH, TLU01_EVT_RCV_CR_THRESH}, 166110e73f9Sschwartz {TLU01_S_EVT_RCV_PST_HDR_CR_EXH, TLU01_EVT_RCV_PST_HDR_CR_EXH}, 167110e73f9Sschwartz {TLU01_S_EVT_RCV_PST_DA_CR_MPS, TLU01_EVT_RCV_PST_DA_CR_MPS}, 168110e73f9Sschwartz {TLU01_S_EVT_RCV_NPST_HDR_CR_EXH, TLU01_EVT_RCV_NPST_HDR_CR_EXH}, 169110e73f9Sschwartz {TLU01_S_EVT_RCVR_L0S, TLU01_EVT_RCVR_L0S}, 170110e73f9Sschwartz {TLU01_S_EVT_RCVR_L0S_TRANS, TLU01_EVT_RCVR_L0S_TRANS}, 171110e73f9Sschwartz {TLU01_S_EVT_XMTR_L0S, TLU01_EVT_XMTR_L0S}, 172110e73f9Sschwartz {TLU01_S_EVT_XMTR_L0S_TRANS, TLU01_EVT_XMTR_L0S_TRANS}, 173110e73f9Sschwartz {TLU01_S_EVT_RCVR_ERR, TLU01_EVT_RCVR_ERR}, 174110e73f9Sschwartz {TLU01_S_EVT_BAD_TLP, TLU01_EVT_BAD_TLP}, 175110e73f9Sschwartz {TLU01_S_EVT_BAD_DLLP, TLU01_EVT_BAD_DLLP}, 176110e73f9Sschwartz {TLU01_S_EVT_REPLAY_ROLLOVER, TLU01_EVT_REPLAY_ROLLOVER}, 177110e73f9Sschwartz {TLU01_S_EVT_REPLAY_TMO, TLU01_EVT_REPLAY_TMO}, 178110e73f9Sschwartz {COMMON_S_CLEAR_PIC, TLU01_EVT_MASK} 179110e73f9Sschwartz }; 180110e73f9Sschwartz 181110e73f9Sschwartz /* 182110e73f9Sschwartz * TLU performance events for counter 2 183110e73f9Sschwartz */ 184110e73f9Sschwartz static fi_kev_mask_t 185110e73f9Sschwartz fire_tlu2_events[] = { 186110e73f9Sschwartz {TLU2_S_EVT_NONE, TLU2_EVT_NONE}, 187110e73f9Sschwartz {TLU2_S_EVT_NON_POST_COMPL_TIME, TLU2_EVT_NON_POST_COMPL_TIME}, 188110e73f9Sschwartz {TLU2_S_EVT_XMT_DATA_WORD, TLU2_EVT_XMT_DATA_WORD}, 189110e73f9Sschwartz {TLU2_S_EVT_RCVD_DATA_WORD, TLU2_EVT_RCVD_DATA_WORD}, 190110e73f9Sschwartz {COMMON_S_CLEAR_PIC, TLU2_EVT_MASK} 191110e73f9Sschwartz }; 192110e73f9Sschwartz 193110e73f9Sschwartz /* 194110e73f9Sschwartz * LPU performance events 195110e73f9Sschwartz */ 196110e73f9Sschwartz static fi_kev_mask_t 197110e73f9Sschwartz fire_lpu_events[] = { 198110e73f9Sschwartz {LPU12_S_EVT_RESET, LPU12_EVT_RESET}, 199110e73f9Sschwartz {LPU12_S_EVT_TLP_RCVD, LPU12_EVT_TLP_RCVD}, 200110e73f9Sschwartz {LPU12_S_EVT_DLLP_RCVD, LPU12_EVT_DLLP_RCVD}, 201110e73f9Sschwartz {LPU12_S_EVT_ACK_DLLP_RCVD, LPU12_EVT_ACK_DLLP_RCVD}, 202110e73f9Sschwartz {LPU12_S_EVT_NAK_DLLP_RCVD, LPU12_EVT_NAK_DLLP_RCVD}, 203110e73f9Sschwartz {LPU12_S_EVT_RETRY_START, LPU12_EVT_RETRY_START}, 204110e73f9Sschwartz {LPU12_S_EVT_REPLAY_TMO, LPU12_EVT_REPLAY_TMO}, 205110e73f9Sschwartz {LPU12_S_EVT_ACK_NAK_LAT_TMO, LPU12_EVT_ACK_NAK_LAT_TMO}, 206110e73f9Sschwartz {LPU12_S_EVT_BAD_DLLP, LPU12_EVT_BAD_DLLP}, 207110e73f9Sschwartz {LPU12_S_EVT_BAD_TLP, LPU12_EVT_BAD_TLP}, 208110e73f9Sschwartz {LPU12_S_EVT_NAK_DLLP_SENT, LPU12_EVT_NAK_DLLP_SENT}, 209110e73f9Sschwartz {LPU12_S_EVT_ACK_DLLP_SENT, LPU12_EVT_ACK_DLLP_SENT}, 210110e73f9Sschwartz {LPU12_S_EVT_RCVR_ERROR, LPU12_EVT_RCVR_ERROR}, 211110e73f9Sschwartz {LPU12_S_EVT_LTSSM_RECOV_ENTRY, LPU12_EVT_LTSSM_RECOV_ENTRY}, 212110e73f9Sschwartz {LPU12_S_EVT_REPLAY_IN_PROG, LPU12_EVT_REPLAY_IN_PROG}, 213110e73f9Sschwartz {LPU12_S_EVT_TLP_XMT_IN_PROG, LPU12_EVT_TLP_XMT_IN_PROG}, 214110e73f9Sschwartz {LPU12_S_EVT_CLK_CYC, LPU12_EVT_CLK_CYC}, 215110e73f9Sschwartz {LPU12_S_EVT_TLP_DLLP_XMT_PROG, LPU12_EVT_TLP_DLLP_XMT_PROG}, 216110e73f9Sschwartz {LPU12_S_EVT_TLP_DLLP_RCV_PROG, LPU12_EVT_TLP_DLLP_RCV_PROG}, 217110e73f9Sschwartz {COMMON_S_CLEAR_PIC, LPU12_EVT_MASK} 218110e73f9Sschwartz }; 219110e73f9Sschwartz 220110e73f9Sschwartz int 221110e73f9Sschwartz fpc_kstat_init(dev_info_t *dip) 222110e73f9Sschwartz { 223110e73f9Sschwartz fire_perfcnt_t i; 224110e73f9Sschwartz int avail; 225110e73f9Sschwartz uint8_t num_inst = 0; 226110e73f9Sschwartz 227110e73f9Sschwartz if (fpc_perfcnt_module_init(dip, &avail) != DDI_SUCCESS) 228110e73f9Sschwartz return (DDI_FAILURE); 229110e73f9Sschwartz 230110e73f9Sschwartz if (avail & PCIE_A_REGS_AVAIL) 231110e73f9Sschwartz num_inst++; 232110e73f9Sschwartz if (avail & PCIE_B_REGS_AVAIL) 233110e73f9Sschwartz num_inst++; 234110e73f9Sschwartz 235110e73f9Sschwartz for (i = jbc; i < MAX_REG_TYPES; i++) { 236110e73f9Sschwartz if (i == jbc) { 237110e73f9Sschwartz if (avail & JBUS_REGS_AVAIL) { 238110e73f9Sschwartz if (fpc_dev_kstat(i, 1) != SUCCESS) 239110e73f9Sschwartz return (DDI_FAILURE); 240110e73f9Sschwartz } 241110e73f9Sschwartz } else { 242110e73f9Sschwartz if (!num_inst) 243110e73f9Sschwartz break; 244110e73f9Sschwartz if (fpc_dev_kstat(i, num_inst) != SUCCESS) 245110e73f9Sschwartz return (DDI_FAILURE); 246110e73f9Sschwartz } 247110e73f9Sschwartz } 248110e73f9Sschwartz 249110e73f9Sschwartz return (DDI_SUCCESS); 250110e73f9Sschwartz } 251110e73f9Sschwartz 252110e73f9Sschwartz static int 253110e73f9Sschwartz fpc_dev_kstat(fire_perfcnt_t reg_group, uint8_t num_inst) 254110e73f9Sschwartz { 255110e73f9Sschwartz int i, base_cntrid, num_cntrs; 256110e73f9Sschwartz uint32_t num_events, num_events2; 257110e73f9Sschwartz char dev_name[DEVICE_NAME_LEN]; 258110e73f9Sschwartz fi_ksinfo_t *ksinfop; 259110e73f9Sschwartz fi_kev_mask_t *fire_events, *fire_events2; 260110e73f9Sschwartz 261110e73f9Sschwartz switch (reg_group) { 262110e73f9Sschwartz case imu: 263*ae53df47Skd93003 (void) strncpy(dev_name, "imu", sizeof (dev_name)); 264110e73f9Sschwartz num_events = sizeof (fire_imu_events) / sizeof (fi_kev_mask_t); 265110e73f9Sschwartz fire_events = fire_imu_events; 266110e73f9Sschwartz num_cntrs = NUM_IMU_COUNTERS; 267110e73f9Sschwartz break; 268110e73f9Sschwartz case mmu: 269*ae53df47Skd93003 (void) strncpy(dev_name, "mmu", sizeof (dev_name)); 270110e73f9Sschwartz num_events = sizeof (fire_mmu_events) / sizeof (fi_kev_mask_t); 271110e73f9Sschwartz fire_events = fire_mmu_events; 272110e73f9Sschwartz num_cntrs = NUM_MMU_COUNTERS; 273110e73f9Sschwartz break; 274110e73f9Sschwartz case lpu: 275*ae53df47Skd93003 (void) strncpy(dev_name, "lpu", sizeof (dev_name)); 276110e73f9Sschwartz num_events = sizeof (fire_lpu_events) / sizeof (fi_kev_mask_t); 277110e73f9Sschwartz fire_events = fire_lpu_events; 278110e73f9Sschwartz num_cntrs = NUM_LPU_COUNTERS; 279110e73f9Sschwartz break; 280110e73f9Sschwartz case tlu: 281*ae53df47Skd93003 (void) strncpy(dev_name, "tlu", sizeof (dev_name)); 282110e73f9Sschwartz num_events = sizeof (fire_tlu_events) / sizeof (fi_kev_mask_t); 283110e73f9Sschwartz num_events2 = sizeof (fire_tlu2_events) / 284110e73f9Sschwartz sizeof (fi_kev_mask_t); 285110e73f9Sschwartz fire_events = fire_tlu_events; 286110e73f9Sschwartz fire_events2 = fire_tlu2_events; 287110e73f9Sschwartz num_cntrs = NUM_TLU_COUNTERS; 288110e73f9Sschwartz break; 289110e73f9Sschwartz case jbc: 290110e73f9Sschwartz (void) strncpy(dev_name, "jbc", sizeof (dev_name)); 291110e73f9Sschwartz num_events = sizeof (fire_jbc_events) / sizeof (fi_kev_mask_t); 292110e73f9Sschwartz fire_events = fire_jbc_events; 293110e73f9Sschwartz num_cntrs = NUM_JBC_COUNTERS; 294110e73f9Sschwartz break; 295110e73f9Sschwartz default: 296110e73f9Sschwartz return (FAILURE); 297110e73f9Sschwartz } 298110e73f9Sschwartz 299110e73f9Sschwartz for (i = 0; i < num_inst; i++) { 300110e73f9Sschwartz ksinfop = (fi_ksinfo_t *)kmem_zalloc(sizeof (fi_ksinfo_t), 301110e73f9Sschwartz KM_SLEEP); 302110e73f9Sschwartz 303110e73f9Sschwartz ksinfop->pic_num_events = num_events; 304110e73f9Sschwartz ksinfop->pic_reg_group = reg_group; 305110e73f9Sschwartz ksinfop->pic_leaf_id = i; 306110e73f9Sschwartz ksinfop->pic_sel_shift[0] = PIC0_EVT_SEL_SHIFT; 307110e73f9Sschwartz 308110e73f9Sschwartz if (reg_group == lpu) 309110e73f9Sschwartz ksinfop->pic_sel_shift[1] = PIC2_EVT_SEL_SHIFT; 310110e73f9Sschwartz else 311110e73f9Sschwartz ksinfop->pic_sel_shift[1] = PIC1_EVT_SEL_SHIFT; 312110e73f9Sschwartz 313110e73f9Sschwartz /* 314110e73f9Sschwartz * All error cleanup (deleting kstats and freeing memory) is 315110e73f9Sschwartz * done in fire_kstat_fini. So we need to save the ksinfop 316110e73f9Sschwartz * pointer before any possible error exit so fire_kstat_fini 317110e73f9Sschwartz * can find it. 318110e73f9Sschwartz */ 319110e73f9Sschwartz if (reg_group == imu) 320110e73f9Sschwartz fi_imu_kstats[i] = ksinfop; 321110e73f9Sschwartz else if (reg_group == mmu) 322110e73f9Sschwartz fi_mmu_kstats[i] = ksinfop; 323110e73f9Sschwartz else if (reg_group == lpu) 324110e73f9Sschwartz fi_lpu_kstats[i] = ksinfop; 325110e73f9Sschwartz else if (reg_group == tlu) 326110e73f9Sschwartz fi_tlu_kstats[i] = ksinfop; 327110e73f9Sschwartz else if (reg_group == jbc) 328110e73f9Sschwartz fi_jbc_kstat = ksinfop; 329110e73f9Sschwartz 330110e73f9Sschwartz /* Create basic pic event-type pair (only once) */ 331110e73f9Sschwartz if (i == 0) { 332110e73f9Sschwartz base_cntrid = 0; 333110e73f9Sschwartz 334110e73f9Sschwartz /* The extra counter for TLU is handled separately */ 335110e73f9Sschwartz if (reg_group == tlu) 336110e73f9Sschwartz num_cntrs--; 337110e73f9Sschwartz 338110e73f9Sschwartz if (fpc_create_name_kstat(dev_name, ksinfop, 339110e73f9Sschwartz fire_events, base_cntrid, num_cntrs) != SUCCESS) 340110e73f9Sschwartz goto err; 341110e73f9Sschwartz 342110e73f9Sschwartz /* 343110e73f9Sschwartz * extra counter for TLU. The events associated with 344110e73f9Sschwartz * this third counter are different from the events 345110e73f9Sschwartz * for the first and second counters. 346110e73f9Sschwartz */ 347110e73f9Sschwartz if (reg_group == tlu) { 348110e73f9Sschwartz ksinfop->pic_sel_shift[2] = PIC2_EVT_SEL_SHIFT; 349110e73f9Sschwartz base_cntrid += num_cntrs; 350110e73f9Sschwartz num_cntrs = 1; 351110e73f9Sschwartz ksinfop->pic_num_events = num_events2; 352110e73f9Sschwartz if (fpc_create_name_kstat(dev_name, ksinfop, 353110e73f9Sschwartz fire_events2, base_cntrid, num_cntrs) 354110e73f9Sschwartz != SUCCESS) 355110e73f9Sschwartz goto err; 356110e73f9Sschwartz 357110e73f9Sschwartz num_cntrs = NUM_TLU_COUNTERS; 358110e73f9Sschwartz } 359110e73f9Sschwartz 360110e73f9Sschwartz } 361110e73f9Sschwartz 362110e73f9Sschwartz /* create counter kstats */ 363110e73f9Sschwartz ksinfop->cntr_ksp = fpc_create_cntr_kstat(dev_name, i, 364110e73f9Sschwartz fpc_cntr_kstat_update, ksinfop, num_cntrs); 365110e73f9Sschwartz if (ksinfop->cntr_ksp == NULL) 366110e73f9Sschwartz goto err; 367110e73f9Sschwartz 368110e73f9Sschwartz } 369110e73f9Sschwartz return (SUCCESS); 370110e73f9Sschwartz err: 371110e73f9Sschwartz return (FAILURE); 372110e73f9Sschwartz 373110e73f9Sschwartz } 374110e73f9Sschwartz 375110e73f9Sschwartz static int 376110e73f9Sschwartz fpc_create_name_kstat(char *name, fi_ksinfo_t *pp, fi_kev_mask_t *ev, 377110e73f9Sschwartz int base, int num_cntrs) 378110e73f9Sschwartz { 379110e73f9Sschwartz int i; 380110e73f9Sschwartz 381110e73f9Sschwartz #ifdef DEBUG 382110e73f9Sschwartz FPC_DBG2("fpc_create_name_kstat: name: %s\n", name); 383110e73f9Sschwartz #endif 384110e73f9Sschwartz 385110e73f9Sschwartz for (i = base; i < (base + num_cntrs); i++) { 386110e73f9Sschwartz pp->pic_name_ksp[i] = fpc_create_picN_kstat(name, i, 387110e73f9Sschwartz pp->pic_sel_shift[i], pp->pic_num_events, ev); 388110e73f9Sschwartz 389110e73f9Sschwartz if (pp->pic_name_ksp[i] == NULL) 390110e73f9Sschwartz return (FAILURE); 391110e73f9Sschwartz } 392110e73f9Sschwartz return (SUCCESS); 393110e73f9Sschwartz } 394110e73f9Sschwartz 395110e73f9Sschwartz /* 396110e73f9Sschwartz * Create the picN kstat. Returns a pointer to the 397110e73f9Sschwartz * kstat which the driver must store to allow it 398110e73f9Sschwartz * to be deleted when necessary. 399110e73f9Sschwartz */ 400110e73f9Sschwartz static kstat_t * 401110e73f9Sschwartz fpc_create_picN_kstat(char *mod_name, int pic, int pic_sel_shift, int num_ev, 402110e73f9Sschwartz fi_kev_mask_t *ev_array) 403110e73f9Sschwartz { 404110e73f9Sschwartz int event; 405110e73f9Sschwartz char pic_name[PIC_STR_LEN]; 406110e73f9Sschwartz kstat_t *picN_ksp = NULL; 407110e73f9Sschwartz struct kstat_named *pic_named_data; 408110e73f9Sschwartz 409110e73f9Sschwartz (void) snprintf(pic_name, sizeof (pic_name), "pic%d", pic); 410110e73f9Sschwartz if ((picN_ksp = kstat_create(mod_name, 0, pic_name, 411110e73f9Sschwartz "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) { 412110e73f9Sschwartz cmn_err(CE_WARN, "%s %s : kstat create failed", 413110e73f9Sschwartz mod_name, pic_name); 414110e73f9Sschwartz return (NULL); 415110e73f9Sschwartz } 416110e73f9Sschwartz 417110e73f9Sschwartz pic_named_data = (struct kstat_named *)picN_ksp->ks_data; 418110e73f9Sschwartz 419110e73f9Sschwartz /* 420110e73f9Sschwartz * Fill up data section of the kstat 421110e73f9Sschwartz * Write event names and their associated pcr masks. 422110e73f9Sschwartz * num_ev - 1 is because CLEAR_PIC is added separately. 423110e73f9Sschwartz */ 424110e73f9Sschwartz for (event = 0; event < num_ev - 1; event++) { 425110e73f9Sschwartz pic_named_data[event].value.ui64 = 426110e73f9Sschwartz (ev_array[event].pcr_mask << pic_sel_shift); 427110e73f9Sschwartz 428110e73f9Sschwartz kstat_named_init(&pic_named_data[event], 429110e73f9Sschwartz ev_array[event].event_name, KSTAT_DATA_UINT64); 430110e73f9Sschwartz } 431110e73f9Sschwartz 432110e73f9Sschwartz /* 433110e73f9Sschwartz * add the clear_pic entry 434110e73f9Sschwartz */ 435110e73f9Sschwartz pic_named_data[event].value.ui64 = 436110e73f9Sschwartz (uint64_t)~(ev_array[event].pcr_mask << pic_sel_shift); 437110e73f9Sschwartz 438110e73f9Sschwartz kstat_named_init(&pic_named_data[event], ev_array[event].event_name, 439110e73f9Sschwartz KSTAT_DATA_UINT64); 440110e73f9Sschwartz 441110e73f9Sschwartz kstat_install(picN_ksp); 442110e73f9Sschwartz 443110e73f9Sschwartz #ifdef DEBUG 444110e73f9Sschwartz FPC_DBG2("fpc_create_picN_kstat: name %s, pic %d, num_ev %d, " 445110e73f9Sschwartz "pic_sel_shift %d\n", mod_name, pic, num_ev, pic_sel_shift); 446110e73f9Sschwartz #endif 447110e73f9Sschwartz 448110e73f9Sschwartz return (picN_ksp); 449110e73f9Sschwartz } 450110e73f9Sschwartz 451110e73f9Sschwartz /* 452110e73f9Sschwartz * Create the "counters" kstat. 453110e73f9Sschwartz */ 454110e73f9Sschwartz static kstat_t * 455110e73f9Sschwartz fpc_create_cntr_kstat(char *name, int instance, int (*update)(kstat_t *, int), 456110e73f9Sschwartz void *ksinfop, int num_pics) 457110e73f9Sschwartz { 458110e73f9Sschwartz int i; 459110e73f9Sschwartz char pic_str[PIC_STR_LEN]; 460110e73f9Sschwartz struct kstat *counters_ksp; 461110e73f9Sschwartz struct kstat_named *counters_named_data; 462110e73f9Sschwartz 463110e73f9Sschwartz #ifdef DEBUG 464110e73f9Sschwartz FPC_DBG1("fpc_create_cntr_kstat: name: %s instance: %d\n", 465110e73f9Sschwartz name, instance); 466110e73f9Sschwartz #endif 467110e73f9Sschwartz 468110e73f9Sschwartz /* 469110e73f9Sschwartz * Size of kstat is num_pics + 1. extra one for pcr. 470110e73f9Sschwartz */ 471110e73f9Sschwartz if ((counters_ksp = kstat_create(name, instance, "counters", "bus", 472110e73f9Sschwartz KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) { 473110e73f9Sschwartz cmn_err(CE_WARN, "kstat_create for %s%d failed", 474110e73f9Sschwartz name, instance); 475110e73f9Sschwartz return (NULL); 476110e73f9Sschwartz } 477110e73f9Sschwartz 478110e73f9Sschwartz counters_named_data = (struct kstat_named *)(counters_ksp->ks_data); 479110e73f9Sschwartz kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64); 480110e73f9Sschwartz 481110e73f9Sschwartz for (i = 0; i < num_pics; i++) { 482110e73f9Sschwartz (void) snprintf(pic_str, sizeof (pic_str), "pic%d", i); 483110e73f9Sschwartz 484110e73f9Sschwartz kstat_named_init(&counters_named_data[i+1], pic_str, 485110e73f9Sschwartz KSTAT_DATA_UINT64); 486110e73f9Sschwartz } 487110e73f9Sschwartz 488110e73f9Sschwartz /* 489110e73f9Sschwartz * Store the reg type and other info. in the kstat's private field 490110e73f9Sschwartz * so that they are available to the update function. 491110e73f9Sschwartz */ 492110e73f9Sschwartz counters_ksp->ks_private = (void *)ksinfop; 493110e73f9Sschwartz counters_ksp->ks_update = update; 494110e73f9Sschwartz 495110e73f9Sschwartz kstat_install(counters_ksp); 496110e73f9Sschwartz 497110e73f9Sschwartz return (counters_ksp); 498110e73f9Sschwartz } 499110e73f9Sschwartz 500110e73f9Sschwartz /* 501110e73f9Sschwartz * kstat update function. Handles reads/writes 502110e73f9Sschwartz * from/to kstat. 503110e73f9Sschwartz */ 504110e73f9Sschwartz static int 505110e73f9Sschwartz fpc_cntr_kstat_update(kstat_t *ksp, int rw) 506110e73f9Sschwartz { 507110e73f9Sschwartz struct kstat_named *data_p; 508110e73f9Sschwartz fi_ksinfo_t *ksinfop = ksp->ks_private; 509110e73f9Sschwartz uint64_t counters[NUM_MAX_COUNTERS]; 510110e73f9Sschwartz uint64_t event; 511110e73f9Sschwartz 512110e73f9Sschwartz data_p = (struct kstat_named *)ksp->ks_data; 513110e73f9Sschwartz 514110e73f9Sschwartz if (rw == KSTAT_WRITE) { 515110e73f9Sschwartz #ifdef DEBUG 516110e73f9Sschwartz FPC_DBG2("fpc_cntr_kstat_update: wr %ld\n", 517110e73f9Sschwartz data_p[0].value.ui64); 518110e73f9Sschwartz #endif 519110e73f9Sschwartz 520110e73f9Sschwartz if (fpc_perfcnt_program(ksinfop->pic_leaf_id, 521110e73f9Sschwartz ksinfop->pic_reg_group, data_p[0].value.ui64) != SUCCESS) 522110e73f9Sschwartz return (EIO); 523110e73f9Sschwartz } else { 524110e73f9Sschwartz counters[2] = 0; 525110e73f9Sschwartz if (fpc_perfcnt_read(ksinfop->pic_leaf_id, 526110e73f9Sschwartz ksinfop->pic_reg_group, &event, counters) != SUCCESS) 527110e73f9Sschwartz return (EIO); 528110e73f9Sschwartz 529110e73f9Sschwartz data_p[0].value.ui64 = event; 530110e73f9Sschwartz data_p[1].value.ui64 = counters[0]; 531110e73f9Sschwartz data_p[2].value.ui64 = counters[1]; 532110e73f9Sschwartz 533110e73f9Sschwartz if (ksinfop->pic_reg_group == tlu) { 534110e73f9Sschwartz data_p[3].value.ui64 = counters[2]; 535110e73f9Sschwartz } 536110e73f9Sschwartz #ifdef DEBUG 537110e73f9Sschwartz FPC_DBG2("fpc_cntr_kstat_update: rd event %ld, cntr0" 538110e73f9Sschwartz " %ld, cntr1 %ld, cntr2 %ld\n", data_p[0].value.ui64, 539110e73f9Sschwartz counters[0], counters[1], counters[2]); 540110e73f9Sschwartz #endif 541110e73f9Sschwartz } 542110e73f9Sschwartz return (0); 543110e73f9Sschwartz } 544110e73f9Sschwartz 545110e73f9Sschwartz void 546110e73f9Sschwartz fpc_kstat_fini(dev_info_t *dip) 547110e73f9Sschwartz { 548110e73f9Sschwartz int i; 549110e73f9Sschwartz 550110e73f9Sschwartz #ifdef DEBUG 551110e73f9Sschwartz FPC_DBG1("fpc_kstat_fini called\n"); 552110e73f9Sschwartz #endif 553110e73f9Sschwartz 554110e73f9Sschwartz for (i = 0; i < NUM_LEAVES; i++) { 555110e73f9Sschwartz /* IMU */ 556110e73f9Sschwartz if (fi_imu_kstats[i] != NULL) { 557110e73f9Sschwartz fpc_delete_name_kstat(fi_imu_kstats[i]); 558110e73f9Sschwartz if (fi_imu_kstats[i]->cntr_ksp != NULL) 559110e73f9Sschwartz kstat_delete(fi_imu_kstats[i]->cntr_ksp); 560110e73f9Sschwartz kmem_free(fi_imu_kstats[i], sizeof (fi_ksinfo_t)); 561110e73f9Sschwartz fi_imu_kstats[i] = NULL; 562110e73f9Sschwartz } 563110e73f9Sschwartz 564110e73f9Sschwartz /* MMU */ 565110e73f9Sschwartz if (fi_mmu_kstats[i] != NULL) { 566110e73f9Sschwartz fpc_delete_name_kstat(fi_mmu_kstats[i]); 567110e73f9Sschwartz if (fi_mmu_kstats[i]->cntr_ksp != NULL) 568110e73f9Sschwartz kstat_delete(fi_mmu_kstats[i]->cntr_ksp); 569110e73f9Sschwartz kmem_free(fi_mmu_kstats[i], sizeof (fi_ksinfo_t)); 570110e73f9Sschwartz fi_mmu_kstats[i] = NULL; 571110e73f9Sschwartz } 572110e73f9Sschwartz 573110e73f9Sschwartz /* LPU */ 574110e73f9Sschwartz if (fi_lpu_kstats[i] != NULL) { 575110e73f9Sschwartz fpc_delete_name_kstat(fi_lpu_kstats[i]); 576110e73f9Sschwartz if (fi_lpu_kstats[i]->cntr_ksp != NULL) 577110e73f9Sschwartz kstat_delete(fi_lpu_kstats[i]->cntr_ksp); 578110e73f9Sschwartz kmem_free(fi_lpu_kstats[i], sizeof (fi_ksinfo_t)); 579110e73f9Sschwartz fi_lpu_kstats[i] = NULL; 580110e73f9Sschwartz } 581110e73f9Sschwartz 582110e73f9Sschwartz /* TLU */ 583110e73f9Sschwartz if (fi_tlu_kstats[i] != NULL) { 584110e73f9Sschwartz fpc_delete_name_kstat(fi_tlu_kstats[i]); 585110e73f9Sschwartz if (fi_tlu_kstats[i]->cntr_ksp != NULL) 586110e73f9Sschwartz kstat_delete(fi_tlu_kstats[i]->cntr_ksp); 587110e73f9Sschwartz kmem_free(fi_tlu_kstats[i], sizeof (fi_ksinfo_t)); 588110e73f9Sschwartz fi_tlu_kstats[i] = NULL; 589110e73f9Sschwartz } 590110e73f9Sschwartz } 591110e73f9Sschwartz 592110e73f9Sschwartz /* JBC */ 593110e73f9Sschwartz if (fi_jbc_kstat != NULL) { 594110e73f9Sschwartz fpc_delete_name_kstat(fi_jbc_kstat); 595110e73f9Sschwartz if (fi_jbc_kstat->cntr_ksp != NULL) 596110e73f9Sschwartz kstat_delete(fi_jbc_kstat->cntr_ksp); 597110e73f9Sschwartz kmem_free(fi_jbc_kstat, sizeof (fi_ksinfo_t)); 598110e73f9Sschwartz fi_jbc_kstat = NULL; 599110e73f9Sschwartz } 600110e73f9Sschwartz 601110e73f9Sschwartz (void) fpc_perfcnt_module_fini(dip); 602110e73f9Sschwartz } 603110e73f9Sschwartz 604110e73f9Sschwartz static void 605110e73f9Sschwartz fpc_delete_name_kstat(fi_ksinfo_t *pp) 606110e73f9Sschwartz { 607110e73f9Sschwartz int i; 608110e73f9Sschwartz 609110e73f9Sschwartz if (pp != NULL) { 610110e73f9Sschwartz for (i = 0; i < NUM_MAX_COUNTERS; i++) { 611110e73f9Sschwartz if (pp->pic_name_ksp[i] != NULL) 612110e73f9Sschwartz kstat_delete(pp->pic_name_ksp[i]); 613110e73f9Sschwartz } 614110e73f9Sschwartz } 615110e73f9Sschwartz } 616