xref: /onnv-gate/usr/src/uts/sun4/io/fpc/fpc-kstats.c (revision 1370:c1bce5cec2ac)
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