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