11370Sschwartz /*
21370Sschwartz * CDDL HEADER START
31370Sschwartz *
41370Sschwartz * The contents of this file are subject to the terms of the
51370Sschwartz * Common Development and Distribution License (the "License").
61370Sschwartz * You may not use this file except in compliance with the License.
71370Sschwartz *
81370Sschwartz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91370Sschwartz * or http://www.opensolaris.org/os/licensing.
101370Sschwartz * See the License for the specific language governing permissions
111370Sschwartz * and limitations under the License.
121370Sschwartz *
131370Sschwartz * When distributing Covered Code, include this CDDL HEADER in each
141370Sschwartz * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151370Sschwartz * If applicable, add the following below this CDDL HEADER, with the
161370Sschwartz * fields enclosed by brackets "[]" replaced with your own identifying
171370Sschwartz * information: Portions Copyright [yyyy] [name of copyright owner]
181370Sschwartz *
191370Sschwartz * CDDL HEADER END
201370Sschwartz */
211370Sschwartz
221370Sschwartz /*
23*3800Skd93003 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
241370Sschwartz * Use is subject to license terms.
251370Sschwartz */
261370Sschwartz
271370Sschwartz #pragma ident "%Z%%M% %I% %E% SMI"
281370Sschwartz
291370Sschwartz #include <sys/types.h>
301370Sschwartz #include <sys/sunddi.h>
311370Sschwartz #include <sys/sunndi.h>
321370Sschwartz #include <sys/kstat.h>
331370Sschwartz #include <fpc.h>
341370Sschwartz
351370Sschwartz /*
361370Sschwartz * CLEAR_PIC is needed by busstat to extract the current event type of a PIC.
371370Sschwartz * There will be an entry for CLEAR_PIC in each fi_kev_mask_t table below, but
381370Sschwartz * they are different from the other entries in that busstat won't show them to
391370Sschwartz * the user.
401370Sschwartz */
41*3800Skd93003 #define DEVICE_NAME_LEN 4
421370Sschwartz #define PIC_STR_LEN 12
431370Sschwartz
441370Sschwartz /*
451370Sschwartz * Data structure used to build array of event-names and pcr-mask values
461370Sschwartz */
471370Sschwartz typedef struct fi_kev_mask {
481370Sschwartz char *event_name;
491370Sschwartz uint64_t pcr_mask;
501370Sschwartz } fi_kev_mask_t;
511370Sschwartz
521370Sschwartz typedef struct fi_ksinfo {
531370Sschwartz uint32_t pic_num_events;
541370Sschwartz uint32_t pic_leaf_id;
551370Sschwartz uint8_t pic_sel_shift[NUM_MAX_COUNTERS];
561370Sschwartz kstat_t *pic_name_ksp[NUM_MAX_COUNTERS];
571370Sschwartz kstat_t *cntr_ksp;
581370Sschwartz fire_perfcnt_t pic_reg_group;
591370Sschwartz } fi_ksinfo_t;
601370Sschwartz
611370Sschwartz static fi_ksinfo_t *fi_imu_kstats[NUM_LEAVES];
621370Sschwartz static fi_ksinfo_t *fi_mmu_kstats[NUM_LEAVES];
631370Sschwartz static fi_ksinfo_t *fi_tlu_kstats[NUM_LEAVES];
641370Sschwartz static fi_ksinfo_t *fi_lpu_kstats[NUM_LEAVES];
651370Sschwartz static fi_ksinfo_t *fi_jbc_kstat;
661370Sschwartz
671370Sschwartz static int fpc_create_name_kstat(char *name, fi_ksinfo_t *pp, fi_kev_mask_t *ev,
681370Sschwartz int base, int num_cntrs);
691370Sschwartz static void fpc_delete_name_kstat(fi_ksinfo_t *pp);
701370Sschwartz static kstat_t *fpc_create_cntr_kstat(char *name, int instance,
711370Sschwartz int (*update)(kstat_t *, int), void *ksinfop, int num_pics);
721370Sschwartz static int fpc_cntr_kstat_update(kstat_t *ksp, int rw);
731370Sschwartz static int fpc_dev_kstat(fire_perfcnt_t reg_group, uint8_t num_inst);
741370Sschwartz static kstat_t *fpc_create_picN_kstat(char *mod_name, int pic,
751370Sschwartz int pic_sel_shift, int num_ev, fi_kev_mask_t *ev_array);
761370Sschwartz /*
771370Sschwartz * Below are event lists, which map an event name specified on the commandline
781370Sschwartz * with a value to program the event register with.
791370Sschwartz *
801370Sschwartz * The last entry will be the mask of the entire event field for the PIC and
811370Sschwartz * counter type.
821370Sschwartz */
831370Sschwartz
841370Sschwartz /*
851370Sschwartz * JBC performance events.
861370Sschwartz */
871370Sschwartz static fi_kev_mask_t
881370Sschwartz fire_jbc_events[] = {
891370Sschwartz {JBC01_S_EVT_NONE, JBC01_EVT_NONE},
901370Sschwartz {JBC01_S_EVT_CLK, JBC01_EVT_CLK},
911370Sschwartz {JBC01_S_EVT_IDLE, JBC01_EVT_IDLE},
921370Sschwartz {JBC01_S_EVT_FIRE, JBC01_EVT_FIRE},
931370Sschwartz {JBC01_S_EVT_READ_LATENCY, JBC01_EVT_READ_LATENCY},
941370Sschwartz {JBC01_S_EVT_READ_SAMPLE, JBC01_EVT_READ_SAMPLE},
951370Sschwartz {JBC01_S_EVT_I2C_PIO, JBC01_EVT_I2C_PIO},
961370Sschwartz {JBC01_S_EVT_EBUS_PIO, JBC01_EVT_EBUS_PIO},
971370Sschwartz {JBC01_S_EVT_RINGA_PIO, JBC01_EVT_RINGA_PIO},
981370Sschwartz {JBC01_S_EVT_RINGB_PIO, JBC01_EVT_RINGB_PIO},
991370Sschwartz {JBC01_S_EVT_PARTIAL_WR, JBC01_EVT_PARTIAL_WR},
1001370Sschwartz {JBC01_S_EVT_TOTAL_WR, JBC01_EVT_TOTAL_WR},
1011370Sschwartz {JBC01_S_EVT_TOTAL_RD, JBC01_EVT_TOTAL_RD},
1021370Sschwartz {JBC01_S_EVT_AOKOFF, JBC01_EVT_AOKOFF},
1031370Sschwartz {JBC01_S_EVT_DOKOFF, JBC01_EVT_DOKOFF},
1041370Sschwartz {JBC01_S_EVT_DAOKOFF, JBC01_EVT_DAOKOFF},
1051370Sschwartz {JBC01_S_EVT_JBUS_COH_XACT, JBC01_EVT_JBUS_COH_XACT},
1061370Sschwartz {JBC01_S_EVT_FIRE_COH_XACT, JBC01_EVT_FIRE_COH_XACT},
1071370Sschwartz {JBC01_S_EVT_JBUS_NCOH_XACT, JBC01_EVT_JBUS_NCOH_XACT},
1081370Sschwartz {JBC01_S_EVT_FGN_IO_HIT, JBC01_EVT_FGN_IO_HIT},
1091370Sschwartz {JBC01_S_EVT_FIRE_WBS, JBC01_EVT_FIRE_WBS},
1101370Sschwartz {JBC01_S_EVT_PCIEA_PIO_WR, JBC01_EVT_PCIEA_PIO_WR},
1111370Sschwartz {JBC01_S_EVT_PCIEA_PIO_RD, JBC01_EVT_PCIEA_PIO_RD},
1121370Sschwartz {JBC01_S_EVT_PCIEB_PIO_WR, JBC01_EVT_PCIEB_PIO_WR},
1131370Sschwartz {JBC01_S_EVT_PCIEB_PIO_RD, JBC01_EVT_PCIEB_PIO_RD},
1141370Sschwartz {COMMON_S_CLEAR_PIC, JBC01_EVT_MASK}
1151370Sschwartz };
1161370Sschwartz
1171370Sschwartz /*
1181370Sschwartz * IMU performance events
1191370Sschwartz */
1201370Sschwartz static fi_kev_mask_t
1211370Sschwartz fire_imu_events[] = {
1221370Sschwartz {IMU01_S_EVT_NONE, IMU01_EVT_NONE},
1231370Sschwartz {IMU01_S_EVT_CLK, IMU01_EVT_CLK},
1241370Sschwartz {IMU01_S_EVT_MONDO, IMU01_EVT_MONDO},
1251370Sschwartz {IMU01_S_EVT_MSI, IMU01_EVT_MSI},
1261370Sschwartz {IMU01_S_EVT_MONDO_NAKS, IMU01_EVT_MONDO_NAKS},
1271370Sschwartz {IMU01_S_EVT_EQ_WR, IMU01_EVT_EQ_WR},
1281370Sschwartz {IMU01_S_EVT_EQ_MONDO, IMU01_EVT_EQ_MONDO},
1291370Sschwartz {COMMON_S_CLEAR_PIC, IMU01_EVT_MASK}
1301370Sschwartz };
1311370Sschwartz
1321370Sschwartz /*
1331370Sschwartz * MMU performance events
1341370Sschwartz */
1351370Sschwartz static fi_kev_mask_t
1361370Sschwartz fire_mmu_events[] = {
1371370Sschwartz {MMU01_S_EVT_NONE, MMU01_EVT_NONE},
1381370Sschwartz {MMU01_S_EVT_CLK, MMU01_EVT_CLK},
1391370Sschwartz {MMU01_S_EVT_TRANS, MMU01_EVT_TRANSL},
1401370Sschwartz {MMU01_S_EVT_STALL, MMU01_EVT_STALL},
1411370Sschwartz {MMU01_S_EVT_TRANSL_MISS, MMU01_EVT_TRANSL_MISS},
1421370Sschwartz {MMU01_S_EVT_TBLWLK_STALL, MMU01_EVT_TBLWLK_STALL},
1431370Sschwartz {MMU01_S_EVT_BYPASS_TRANSL, MMU01_EVT_BYPASS_TRANSL},
1441370Sschwartz {MMU01_S_EVT_TRANSL_TRANSL, MMU01_EVT_TRANSL_TRANSL},
1451370Sschwartz {MMU01_S_EVT_FLOW_CNTL_STALL, MMU01_EVT_FLOW_CNTL_STALL},
1461370Sschwartz {MMU01_S_EVT_FLUSH_CACHE_ENT, MMU01_EVT_FLUSH_CACHE_ENT},
1471370Sschwartz {COMMON_S_CLEAR_PIC, MMU01_EVT_MASK}
1481370Sschwartz };
1491370Sschwartz
1501370Sschwartz /*
1511370Sschwartz * TLU performance events for counters 0 and 1
1521370Sschwartz */
1531370Sschwartz static fi_kev_mask_t
1541370Sschwartz fire_tlu_events[] = {
1551370Sschwartz {TLU01_S_EVT_NONE, TLU01_EVT_NONE},
1561370Sschwartz {TLU01_S_EVT_CLK, TLU01_EVT_CLK},
1571370Sschwartz {TLU01_S_EVT_COMPL, TLU01_EVT_COMPL},
1581370Sschwartz {TLU01_S_EVT_XMT_POST_CR_UNAV, TLU01_EVT_XMT_POST_CR_UNAV},
1591370Sschwartz {TLU01_S_EVT_XMT_NPOST_CR_UNAV, TLU01_EVT_XMT_NPOST_CR_UNAV},
1601370Sschwartz {TLU01_S_EVT_XMT_CMPL_CR_UNAV, TLU01_EVT_XMT_CMPL_CR_UNAV},
1611370Sschwartz {TLU01_S_EVT_XMT_ANY_CR_UNAV, TLU01_EVT_XMT_ANY_CR_UNAV},
1621370Sschwartz {TLU01_S_EVT_RETRY_CR_UNAV, TLU01_EVT_RETRY_CR_UNAV},
1631370Sschwartz {TLU01_S_EVT_MEMRD_PKT_RCVD, TLU01_EVT_MEMRD_PKT_RCVD},
1641370Sschwartz {TLU01_S_EVT_MEMWR_PKT_RCVD, TLU01_EVT_MEMWR_PKT_RCVD},
1651370Sschwartz {TLU01_S_EVT_RCV_CR_THRESH, TLU01_EVT_RCV_CR_THRESH},
1661370Sschwartz {TLU01_S_EVT_RCV_PST_HDR_CR_EXH, TLU01_EVT_RCV_PST_HDR_CR_EXH},
1671370Sschwartz {TLU01_S_EVT_RCV_PST_DA_CR_MPS, TLU01_EVT_RCV_PST_DA_CR_MPS},
1681370Sschwartz {TLU01_S_EVT_RCV_NPST_HDR_CR_EXH, TLU01_EVT_RCV_NPST_HDR_CR_EXH},
1691370Sschwartz {TLU01_S_EVT_RCVR_L0S, TLU01_EVT_RCVR_L0S},
1701370Sschwartz {TLU01_S_EVT_RCVR_L0S_TRANS, TLU01_EVT_RCVR_L0S_TRANS},
1711370Sschwartz {TLU01_S_EVT_XMTR_L0S, TLU01_EVT_XMTR_L0S},
1721370Sschwartz {TLU01_S_EVT_XMTR_L0S_TRANS, TLU01_EVT_XMTR_L0S_TRANS},
1731370Sschwartz {TLU01_S_EVT_RCVR_ERR, TLU01_EVT_RCVR_ERR},
1741370Sschwartz {TLU01_S_EVT_BAD_TLP, TLU01_EVT_BAD_TLP},
1751370Sschwartz {TLU01_S_EVT_BAD_DLLP, TLU01_EVT_BAD_DLLP},
1761370Sschwartz {TLU01_S_EVT_REPLAY_ROLLOVER, TLU01_EVT_REPLAY_ROLLOVER},
1771370Sschwartz {TLU01_S_EVT_REPLAY_TMO, TLU01_EVT_REPLAY_TMO},
1781370Sschwartz {COMMON_S_CLEAR_PIC, TLU01_EVT_MASK}
1791370Sschwartz };
1801370Sschwartz
1811370Sschwartz /*
1821370Sschwartz * TLU performance events for counter 2
1831370Sschwartz */
1841370Sschwartz static fi_kev_mask_t
1851370Sschwartz fire_tlu2_events[] = {
1861370Sschwartz {TLU2_S_EVT_NONE, TLU2_EVT_NONE},
1871370Sschwartz {TLU2_S_EVT_NON_POST_COMPL_TIME, TLU2_EVT_NON_POST_COMPL_TIME},
1881370Sschwartz {TLU2_S_EVT_XMT_DATA_WORD, TLU2_EVT_XMT_DATA_WORD},
1891370Sschwartz {TLU2_S_EVT_RCVD_DATA_WORD, TLU2_EVT_RCVD_DATA_WORD},
1901370Sschwartz {COMMON_S_CLEAR_PIC, TLU2_EVT_MASK}
1911370Sschwartz };
1921370Sschwartz
1931370Sschwartz /*
1941370Sschwartz * LPU performance events
1951370Sschwartz */
1961370Sschwartz static fi_kev_mask_t
1971370Sschwartz fire_lpu_events[] = {
1981370Sschwartz {LPU12_S_EVT_RESET, LPU12_EVT_RESET},
1991370Sschwartz {LPU12_S_EVT_TLP_RCVD, LPU12_EVT_TLP_RCVD},
2001370Sschwartz {LPU12_S_EVT_DLLP_RCVD, LPU12_EVT_DLLP_RCVD},
2011370Sschwartz {LPU12_S_EVT_ACK_DLLP_RCVD, LPU12_EVT_ACK_DLLP_RCVD},
2021370Sschwartz {LPU12_S_EVT_NAK_DLLP_RCVD, LPU12_EVT_NAK_DLLP_RCVD},
2031370Sschwartz {LPU12_S_EVT_RETRY_START, LPU12_EVT_RETRY_START},
2041370Sschwartz {LPU12_S_EVT_REPLAY_TMO, LPU12_EVT_REPLAY_TMO},
2051370Sschwartz {LPU12_S_EVT_ACK_NAK_LAT_TMO, LPU12_EVT_ACK_NAK_LAT_TMO},
2061370Sschwartz {LPU12_S_EVT_BAD_DLLP, LPU12_EVT_BAD_DLLP},
2071370Sschwartz {LPU12_S_EVT_BAD_TLP, LPU12_EVT_BAD_TLP},
2081370Sschwartz {LPU12_S_EVT_NAK_DLLP_SENT, LPU12_EVT_NAK_DLLP_SENT},
2091370Sschwartz {LPU12_S_EVT_ACK_DLLP_SENT, LPU12_EVT_ACK_DLLP_SENT},
2101370Sschwartz {LPU12_S_EVT_RCVR_ERROR, LPU12_EVT_RCVR_ERROR},
2111370Sschwartz {LPU12_S_EVT_LTSSM_RECOV_ENTRY, LPU12_EVT_LTSSM_RECOV_ENTRY},
2121370Sschwartz {LPU12_S_EVT_REPLAY_IN_PROG, LPU12_EVT_REPLAY_IN_PROG},
2131370Sschwartz {LPU12_S_EVT_TLP_XMT_IN_PROG, LPU12_EVT_TLP_XMT_IN_PROG},
2141370Sschwartz {LPU12_S_EVT_CLK_CYC, LPU12_EVT_CLK_CYC},
2151370Sschwartz {LPU12_S_EVT_TLP_DLLP_XMT_PROG, LPU12_EVT_TLP_DLLP_XMT_PROG},
2161370Sschwartz {LPU12_S_EVT_TLP_DLLP_RCV_PROG, LPU12_EVT_TLP_DLLP_RCV_PROG},
2171370Sschwartz {COMMON_S_CLEAR_PIC, LPU12_EVT_MASK}
2181370Sschwartz };
2191370Sschwartz
2201370Sschwartz int
fpc_kstat_init(dev_info_t * dip)2211370Sschwartz fpc_kstat_init(dev_info_t *dip)
2221370Sschwartz {
2231370Sschwartz fire_perfcnt_t i;
2241370Sschwartz int avail;
2251370Sschwartz uint8_t num_inst = 0;
2261370Sschwartz
2271370Sschwartz if (fpc_perfcnt_module_init(dip, &avail) != DDI_SUCCESS)
2281370Sschwartz return (DDI_FAILURE);
2291370Sschwartz
2301370Sschwartz if (avail & PCIE_A_REGS_AVAIL)
2311370Sschwartz num_inst++;
2321370Sschwartz if (avail & PCIE_B_REGS_AVAIL)
2331370Sschwartz num_inst++;
2341370Sschwartz
2351370Sschwartz for (i = jbc; i < MAX_REG_TYPES; i++) {
2361370Sschwartz if (i == jbc) {
2371370Sschwartz if (avail & JBUS_REGS_AVAIL) {
2381370Sschwartz if (fpc_dev_kstat(i, 1) != SUCCESS)
2391370Sschwartz return (DDI_FAILURE);
2401370Sschwartz }
2411370Sschwartz } else {
2421370Sschwartz if (!num_inst)
2431370Sschwartz break;
2441370Sschwartz if (fpc_dev_kstat(i, num_inst) != SUCCESS)
2451370Sschwartz return (DDI_FAILURE);
2461370Sschwartz }
2471370Sschwartz }
2481370Sschwartz
2491370Sschwartz return (DDI_SUCCESS);
2501370Sschwartz }
2511370Sschwartz
2521370Sschwartz static int
fpc_dev_kstat(fire_perfcnt_t reg_group,uint8_t num_inst)2531370Sschwartz fpc_dev_kstat(fire_perfcnt_t reg_group, uint8_t num_inst)
2541370Sschwartz {
2551370Sschwartz int i, base_cntrid, num_cntrs;
2561370Sschwartz uint32_t num_events, num_events2;
2571370Sschwartz char dev_name[DEVICE_NAME_LEN];
2581370Sschwartz fi_ksinfo_t *ksinfop;
2591370Sschwartz fi_kev_mask_t *fire_events, *fire_events2;
2601370Sschwartz
2611370Sschwartz switch (reg_group) {
2621370Sschwartz case imu:
263*3800Skd93003 (void) strncpy(dev_name, "imu", sizeof (dev_name));
2641370Sschwartz num_events = sizeof (fire_imu_events) / sizeof (fi_kev_mask_t);
2651370Sschwartz fire_events = fire_imu_events;
2661370Sschwartz num_cntrs = NUM_IMU_COUNTERS;
2671370Sschwartz break;
2681370Sschwartz case mmu:
269*3800Skd93003 (void) strncpy(dev_name, "mmu", sizeof (dev_name));
2701370Sschwartz num_events = sizeof (fire_mmu_events) / sizeof (fi_kev_mask_t);
2711370Sschwartz fire_events = fire_mmu_events;
2721370Sschwartz num_cntrs = NUM_MMU_COUNTERS;
2731370Sschwartz break;
2741370Sschwartz case lpu:
275*3800Skd93003 (void) strncpy(dev_name, "lpu", sizeof (dev_name));
2761370Sschwartz num_events = sizeof (fire_lpu_events) / sizeof (fi_kev_mask_t);
2771370Sschwartz fire_events = fire_lpu_events;
2781370Sschwartz num_cntrs = NUM_LPU_COUNTERS;
2791370Sschwartz break;
2801370Sschwartz case tlu:
281*3800Skd93003 (void) strncpy(dev_name, "tlu", sizeof (dev_name));
2821370Sschwartz num_events = sizeof (fire_tlu_events) / sizeof (fi_kev_mask_t);
2831370Sschwartz num_events2 = sizeof (fire_tlu2_events) /
2841370Sschwartz sizeof (fi_kev_mask_t);
2851370Sschwartz fire_events = fire_tlu_events;
2861370Sschwartz fire_events2 = fire_tlu2_events;
2871370Sschwartz num_cntrs = NUM_TLU_COUNTERS;
2881370Sschwartz break;
2891370Sschwartz case jbc:
2901370Sschwartz (void) strncpy(dev_name, "jbc", sizeof (dev_name));
2911370Sschwartz num_events = sizeof (fire_jbc_events) / sizeof (fi_kev_mask_t);
2921370Sschwartz fire_events = fire_jbc_events;
2931370Sschwartz num_cntrs = NUM_JBC_COUNTERS;
2941370Sschwartz break;
2951370Sschwartz default:
2961370Sschwartz return (FAILURE);
2971370Sschwartz }
2981370Sschwartz
2991370Sschwartz for (i = 0; i < num_inst; i++) {
3001370Sschwartz ksinfop = (fi_ksinfo_t *)kmem_zalloc(sizeof (fi_ksinfo_t),
3011370Sschwartz KM_SLEEP);
3021370Sschwartz
3031370Sschwartz ksinfop->pic_num_events = num_events;
3041370Sschwartz ksinfop->pic_reg_group = reg_group;
3051370Sschwartz ksinfop->pic_leaf_id = i;
3061370Sschwartz ksinfop->pic_sel_shift[0] = PIC0_EVT_SEL_SHIFT;
3071370Sschwartz
3081370Sschwartz if (reg_group == lpu)
3091370Sschwartz ksinfop->pic_sel_shift[1] = PIC2_EVT_SEL_SHIFT;
3101370Sschwartz else
3111370Sschwartz ksinfop->pic_sel_shift[1] = PIC1_EVT_SEL_SHIFT;
3121370Sschwartz
3131370Sschwartz /*
3141370Sschwartz * All error cleanup (deleting kstats and freeing memory) is
3151370Sschwartz * done in fire_kstat_fini. So we need to save the ksinfop
3161370Sschwartz * pointer before any possible error exit so fire_kstat_fini
3171370Sschwartz * can find it.
3181370Sschwartz */
3191370Sschwartz if (reg_group == imu)
3201370Sschwartz fi_imu_kstats[i] = ksinfop;
3211370Sschwartz else if (reg_group == mmu)
3221370Sschwartz fi_mmu_kstats[i] = ksinfop;
3231370Sschwartz else if (reg_group == lpu)
3241370Sschwartz fi_lpu_kstats[i] = ksinfop;
3251370Sschwartz else if (reg_group == tlu)
3261370Sschwartz fi_tlu_kstats[i] = ksinfop;
3271370Sschwartz else if (reg_group == jbc)
3281370Sschwartz fi_jbc_kstat = ksinfop;
3291370Sschwartz
3301370Sschwartz /* Create basic pic event-type pair (only once) */
3311370Sschwartz if (i == 0) {
3321370Sschwartz base_cntrid = 0;
3331370Sschwartz
3341370Sschwartz /* The extra counter for TLU is handled separately */
3351370Sschwartz if (reg_group == tlu)
3361370Sschwartz num_cntrs--;
3371370Sschwartz
3381370Sschwartz if (fpc_create_name_kstat(dev_name, ksinfop,
3391370Sschwartz fire_events, base_cntrid, num_cntrs) != SUCCESS)
3401370Sschwartz goto err;
3411370Sschwartz
3421370Sschwartz /*
3431370Sschwartz * extra counter for TLU. The events associated with
3441370Sschwartz * this third counter are different from the events
3451370Sschwartz * for the first and second counters.
3461370Sschwartz */
3471370Sschwartz if (reg_group == tlu) {
3481370Sschwartz ksinfop->pic_sel_shift[2] = PIC2_EVT_SEL_SHIFT;
3491370Sschwartz base_cntrid += num_cntrs;
3501370Sschwartz num_cntrs = 1;
3511370Sschwartz ksinfop->pic_num_events = num_events2;
3521370Sschwartz if (fpc_create_name_kstat(dev_name, ksinfop,
3531370Sschwartz fire_events2, base_cntrid, num_cntrs)
3541370Sschwartz != SUCCESS)
3551370Sschwartz goto err;
3561370Sschwartz
3571370Sschwartz num_cntrs = NUM_TLU_COUNTERS;
3581370Sschwartz }
3591370Sschwartz
3601370Sschwartz }
3611370Sschwartz
3621370Sschwartz /* create counter kstats */
3631370Sschwartz ksinfop->cntr_ksp = fpc_create_cntr_kstat(dev_name, i,
3641370Sschwartz fpc_cntr_kstat_update, ksinfop, num_cntrs);
3651370Sschwartz if (ksinfop->cntr_ksp == NULL)
3661370Sschwartz goto err;
3671370Sschwartz
3681370Sschwartz }
3691370Sschwartz return (SUCCESS);
3701370Sschwartz err:
3711370Sschwartz return (FAILURE);
3721370Sschwartz
3731370Sschwartz }
3741370Sschwartz
3751370Sschwartz static int
fpc_create_name_kstat(char * name,fi_ksinfo_t * pp,fi_kev_mask_t * ev,int base,int num_cntrs)3761370Sschwartz fpc_create_name_kstat(char *name, fi_ksinfo_t *pp, fi_kev_mask_t *ev,
3771370Sschwartz int base, int num_cntrs)
3781370Sschwartz {
3791370Sschwartz int i;
3801370Sschwartz
3811370Sschwartz #ifdef DEBUG
3821370Sschwartz FPC_DBG2("fpc_create_name_kstat: name: %s\n", name);
3831370Sschwartz #endif
3841370Sschwartz
3851370Sschwartz for (i = base; i < (base + num_cntrs); i++) {
3861370Sschwartz pp->pic_name_ksp[i] = fpc_create_picN_kstat(name, i,
3871370Sschwartz pp->pic_sel_shift[i], pp->pic_num_events, ev);
3881370Sschwartz
3891370Sschwartz if (pp->pic_name_ksp[i] == NULL)
3901370Sschwartz return (FAILURE);
3911370Sschwartz }
3921370Sschwartz return (SUCCESS);
3931370Sschwartz }
3941370Sschwartz
3951370Sschwartz /*
3961370Sschwartz * Create the picN kstat. Returns a pointer to the
3971370Sschwartz * kstat which the driver must store to allow it
3981370Sschwartz * to be deleted when necessary.
3991370Sschwartz */
4001370Sschwartz static kstat_t *
fpc_create_picN_kstat(char * mod_name,int pic,int pic_sel_shift,int num_ev,fi_kev_mask_t * ev_array)4011370Sschwartz fpc_create_picN_kstat(char *mod_name, int pic, int pic_sel_shift, int num_ev,
4021370Sschwartz fi_kev_mask_t *ev_array)
4031370Sschwartz {
4041370Sschwartz int event;
4051370Sschwartz char pic_name[PIC_STR_LEN];
4061370Sschwartz kstat_t *picN_ksp = NULL;
4071370Sschwartz struct kstat_named *pic_named_data;
4081370Sschwartz
4091370Sschwartz (void) snprintf(pic_name, sizeof (pic_name), "pic%d", pic);
4101370Sschwartz if ((picN_ksp = kstat_create(mod_name, 0, pic_name,
4111370Sschwartz "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) {
4121370Sschwartz cmn_err(CE_WARN, "%s %s : kstat create failed",
4131370Sschwartz mod_name, pic_name);
4141370Sschwartz return (NULL);
4151370Sschwartz }
4161370Sschwartz
4171370Sschwartz pic_named_data = (struct kstat_named *)picN_ksp->ks_data;
4181370Sschwartz
4191370Sschwartz /*
4201370Sschwartz * Fill up data section of the kstat
4211370Sschwartz * Write event names and their associated pcr masks.
4221370Sschwartz * num_ev - 1 is because CLEAR_PIC is added separately.
4231370Sschwartz */
4241370Sschwartz for (event = 0; event < num_ev - 1; event++) {
4251370Sschwartz pic_named_data[event].value.ui64 =
4261370Sschwartz (ev_array[event].pcr_mask << pic_sel_shift);
4271370Sschwartz
4281370Sschwartz kstat_named_init(&pic_named_data[event],
4291370Sschwartz ev_array[event].event_name, KSTAT_DATA_UINT64);
4301370Sschwartz }
4311370Sschwartz
4321370Sschwartz /*
4331370Sschwartz * add the clear_pic entry
4341370Sschwartz */
4351370Sschwartz pic_named_data[event].value.ui64 =
4361370Sschwartz (uint64_t)~(ev_array[event].pcr_mask << pic_sel_shift);
4371370Sschwartz
4381370Sschwartz kstat_named_init(&pic_named_data[event], ev_array[event].event_name,
4391370Sschwartz KSTAT_DATA_UINT64);
4401370Sschwartz
4411370Sschwartz kstat_install(picN_ksp);
4421370Sschwartz
4431370Sschwartz #ifdef DEBUG
4441370Sschwartz FPC_DBG2("fpc_create_picN_kstat: name %s, pic %d, num_ev %d, "
4451370Sschwartz "pic_sel_shift %d\n", mod_name, pic, num_ev, pic_sel_shift);
4461370Sschwartz #endif
4471370Sschwartz
4481370Sschwartz return (picN_ksp);
4491370Sschwartz }
4501370Sschwartz
4511370Sschwartz /*
4521370Sschwartz * Create the "counters" kstat.
4531370Sschwartz */
4541370Sschwartz static kstat_t *
fpc_create_cntr_kstat(char * name,int instance,int (* update)(kstat_t *,int),void * ksinfop,int num_pics)4551370Sschwartz fpc_create_cntr_kstat(char *name, int instance, int (*update)(kstat_t *, int),
4561370Sschwartz void *ksinfop, int num_pics)
4571370Sschwartz {
4581370Sschwartz int i;
4591370Sschwartz char pic_str[PIC_STR_LEN];
4601370Sschwartz struct kstat *counters_ksp;
4611370Sschwartz struct kstat_named *counters_named_data;
4621370Sschwartz
4631370Sschwartz #ifdef DEBUG
4641370Sschwartz FPC_DBG1("fpc_create_cntr_kstat: name: %s instance: %d\n",
4651370Sschwartz name, instance);
4661370Sschwartz #endif
4671370Sschwartz
4681370Sschwartz /*
4691370Sschwartz * Size of kstat is num_pics + 1. extra one for pcr.
4701370Sschwartz */
4711370Sschwartz if ((counters_ksp = kstat_create(name, instance, "counters", "bus",
4721370Sschwartz KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) {
4731370Sschwartz cmn_err(CE_WARN, "kstat_create for %s%d failed",
4741370Sschwartz name, instance);
4751370Sschwartz return (NULL);
4761370Sschwartz }
4771370Sschwartz
4781370Sschwartz counters_named_data = (struct kstat_named *)(counters_ksp->ks_data);
4791370Sschwartz kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64);
4801370Sschwartz
4811370Sschwartz for (i = 0; i < num_pics; i++) {
4821370Sschwartz (void) snprintf(pic_str, sizeof (pic_str), "pic%d", i);
4831370Sschwartz
4841370Sschwartz kstat_named_init(&counters_named_data[i+1], pic_str,
4851370Sschwartz KSTAT_DATA_UINT64);
4861370Sschwartz }
4871370Sschwartz
4881370Sschwartz /*
4891370Sschwartz * Store the reg type and other info. in the kstat's private field
4901370Sschwartz * so that they are available to the update function.
4911370Sschwartz */
4921370Sschwartz counters_ksp->ks_private = (void *)ksinfop;
4931370Sschwartz counters_ksp->ks_update = update;
4941370Sschwartz
4951370Sschwartz kstat_install(counters_ksp);
4961370Sschwartz
4971370Sschwartz return (counters_ksp);
4981370Sschwartz }
4991370Sschwartz
5001370Sschwartz /*
5011370Sschwartz * kstat update function. Handles reads/writes
5021370Sschwartz * from/to kstat.
5031370Sschwartz */
5041370Sschwartz static int
fpc_cntr_kstat_update(kstat_t * ksp,int rw)5051370Sschwartz fpc_cntr_kstat_update(kstat_t *ksp, int rw)
5061370Sschwartz {
5071370Sschwartz struct kstat_named *data_p;
5081370Sschwartz fi_ksinfo_t *ksinfop = ksp->ks_private;
5091370Sschwartz uint64_t counters[NUM_MAX_COUNTERS];
5101370Sschwartz uint64_t event;
5111370Sschwartz
5121370Sschwartz data_p = (struct kstat_named *)ksp->ks_data;
5131370Sschwartz
5141370Sschwartz if (rw == KSTAT_WRITE) {
5151370Sschwartz #ifdef DEBUG
5161370Sschwartz FPC_DBG2("fpc_cntr_kstat_update: wr %ld\n",
5171370Sschwartz data_p[0].value.ui64);
5181370Sschwartz #endif
5191370Sschwartz
5201370Sschwartz if (fpc_perfcnt_program(ksinfop->pic_leaf_id,
5211370Sschwartz ksinfop->pic_reg_group, data_p[0].value.ui64) != SUCCESS)
5221370Sschwartz return (EIO);
5231370Sschwartz } else {
5241370Sschwartz counters[2] = 0;
5251370Sschwartz if (fpc_perfcnt_read(ksinfop->pic_leaf_id,
5261370Sschwartz ksinfop->pic_reg_group, &event, counters) != SUCCESS)
5271370Sschwartz return (EIO);
5281370Sschwartz
5291370Sschwartz data_p[0].value.ui64 = event;
5301370Sschwartz data_p[1].value.ui64 = counters[0];
5311370Sschwartz data_p[2].value.ui64 = counters[1];
5321370Sschwartz
5331370Sschwartz if (ksinfop->pic_reg_group == tlu) {
5341370Sschwartz data_p[3].value.ui64 = counters[2];
5351370Sschwartz }
5361370Sschwartz #ifdef DEBUG
5371370Sschwartz FPC_DBG2("fpc_cntr_kstat_update: rd event %ld, cntr0"
5381370Sschwartz " %ld, cntr1 %ld, cntr2 %ld\n", data_p[0].value.ui64,
5391370Sschwartz counters[0], counters[1], counters[2]);
5401370Sschwartz #endif
5411370Sschwartz }
5421370Sschwartz return (0);
5431370Sschwartz }
5441370Sschwartz
5451370Sschwartz void
fpc_kstat_fini(dev_info_t * dip)5461370Sschwartz fpc_kstat_fini(dev_info_t *dip)
5471370Sschwartz {
5481370Sschwartz int i;
5491370Sschwartz
5501370Sschwartz #ifdef DEBUG
5511370Sschwartz FPC_DBG1("fpc_kstat_fini called\n");
5521370Sschwartz #endif
5531370Sschwartz
5541370Sschwartz for (i = 0; i < NUM_LEAVES; i++) {
5551370Sschwartz /* IMU */
5561370Sschwartz if (fi_imu_kstats[i] != NULL) {
5571370Sschwartz fpc_delete_name_kstat(fi_imu_kstats[i]);
5581370Sschwartz if (fi_imu_kstats[i]->cntr_ksp != NULL)
5591370Sschwartz kstat_delete(fi_imu_kstats[i]->cntr_ksp);
5601370Sschwartz kmem_free(fi_imu_kstats[i], sizeof (fi_ksinfo_t));
5611370Sschwartz fi_imu_kstats[i] = NULL;
5621370Sschwartz }
5631370Sschwartz
5641370Sschwartz /* MMU */
5651370Sschwartz if (fi_mmu_kstats[i] != NULL) {
5661370Sschwartz fpc_delete_name_kstat(fi_mmu_kstats[i]);
5671370Sschwartz if (fi_mmu_kstats[i]->cntr_ksp != NULL)
5681370Sschwartz kstat_delete(fi_mmu_kstats[i]->cntr_ksp);
5691370Sschwartz kmem_free(fi_mmu_kstats[i], sizeof (fi_ksinfo_t));
5701370Sschwartz fi_mmu_kstats[i] = NULL;
5711370Sschwartz }
5721370Sschwartz
5731370Sschwartz /* LPU */
5741370Sschwartz if (fi_lpu_kstats[i] != NULL) {
5751370Sschwartz fpc_delete_name_kstat(fi_lpu_kstats[i]);
5761370Sschwartz if (fi_lpu_kstats[i]->cntr_ksp != NULL)
5771370Sschwartz kstat_delete(fi_lpu_kstats[i]->cntr_ksp);
5781370Sschwartz kmem_free(fi_lpu_kstats[i], sizeof (fi_ksinfo_t));
5791370Sschwartz fi_lpu_kstats[i] = NULL;
5801370Sschwartz }
5811370Sschwartz
5821370Sschwartz /* TLU */
5831370Sschwartz if (fi_tlu_kstats[i] != NULL) {
5841370Sschwartz fpc_delete_name_kstat(fi_tlu_kstats[i]);
5851370Sschwartz if (fi_tlu_kstats[i]->cntr_ksp != NULL)
5861370Sschwartz kstat_delete(fi_tlu_kstats[i]->cntr_ksp);
5871370Sschwartz kmem_free(fi_tlu_kstats[i], sizeof (fi_ksinfo_t));
5881370Sschwartz fi_tlu_kstats[i] = NULL;
5891370Sschwartz }
5901370Sschwartz }
5911370Sschwartz
5921370Sschwartz /* JBC */
5931370Sschwartz if (fi_jbc_kstat != NULL) {
5941370Sschwartz fpc_delete_name_kstat(fi_jbc_kstat);
5951370Sschwartz if (fi_jbc_kstat->cntr_ksp != NULL)
5961370Sschwartz kstat_delete(fi_jbc_kstat->cntr_ksp);
5971370Sschwartz kmem_free(fi_jbc_kstat, sizeof (fi_ksinfo_t));
5981370Sschwartz fi_jbc_kstat = NULL;
5991370Sschwartz }
6001370Sschwartz
6011370Sschwartz (void) fpc_perfcnt_module_fini(dip);
6021370Sschwartz }
6031370Sschwartz
6041370Sschwartz static void
fpc_delete_name_kstat(fi_ksinfo_t * pp)6051370Sschwartz fpc_delete_name_kstat(fi_ksinfo_t *pp)
6061370Sschwartz {
6071370Sschwartz int i;
6081370Sschwartz
6091370Sschwartz if (pp != NULL) {
6101370Sschwartz for (i = 0; i < NUM_MAX_COUNTERS; i++) {
6111370Sschwartz if (pp->pic_name_ksp[i] != NULL)
6121370Sschwartz kstat_delete(pp->pic_name_ksp[i]);
6131370Sschwartz }
6141370Sschwartz }
6151370Sschwartz }
616