xref: /titanic_44/usr/src/uts/sun4/io/fpc/fpc-kstats.c (revision ae53df47ce6510c89a72cb9868322dc60bce861b)
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
fpc_kstat_init(dev_info_t * dip)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
fpc_dev_kstat(fire_perfcnt_t reg_group,uint8_t num_inst)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
fpc_create_name_kstat(char * name,fi_ksinfo_t * pp,fi_kev_mask_t * ev,int base,int num_cntrs)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 *
fpc_create_picN_kstat(char * mod_name,int pic,int pic_sel_shift,int num_ev,fi_kev_mask_t * ev_array)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 *
fpc_create_cntr_kstat(char * name,int instance,int (* update)(kstat_t *,int),void * ksinfop,int num_pics)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
fpc_cntr_kstat_update(kstat_t * ksp,int rw)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
fpc_kstat_fini(dev_info_t * dip)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
fpc_delete_name_kstat(fi_ksinfo_t * pp)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