xref: /onnv-gate/usr/src/uts/sun4/io/fpc/fpc-impl.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/param.h>
30*1370Sschwartz #include <sys/types.h>
31*1370Sschwartz #include <sys/errno.h>
32*1370Sschwartz #include <sys/kmem.h>
33*1370Sschwartz #include <sys/sunddi.h>
34*1370Sschwartz #include <sys/disp.h>
35*1370Sschwartz #include <fpc.h>
36*1370Sschwartz #include <fpc-impl.h>
37*1370Sschwartz 
38*1370Sschwartz #define	BOUNDS_CHECK_FAILS(arg, max)	((arg < 0) && (arg >= max))
39*1370Sschwartz 
40*1370Sschwartz static int this_node = 0;
41*1370Sschwartz node_data_t node_data[NUM_LEAVES];
42*1370Sschwartz 
43*1370Sschwartz int fpc_debug = 0;
44*1370Sschwartz 
45*1370Sschwartz static int counters_per_type[MAX_REG_TYPES] = {
46*1370Sschwartz 	NUM_JBC_COUNTERS,
47*1370Sschwartz 	NUM_IMU_COUNTERS,
48*1370Sschwartz 	NUM_MMU_COUNTERS,
49*1370Sschwartz 	NUM_TLU_COUNTERS,
50*1370Sschwartz 	NUM_LPU_COUNTERS
51*1370Sschwartz };
52*1370Sschwartz 
53*1370Sschwartz static int first_reg_of_type[MAX_REG_TYPES];
54*1370Sschwartz 
55*1370Sschwartz static uint64_t event_field_mask[NUM_TOTAL_COUNTERS] = {
56*1370Sschwartz 	JBC_PIC0_EVT_MASK,		/* JBC counter 0 */
57*1370Sschwartz 	JBC_PIC1_EVT_MASK,		/* JBC counter 1 */
58*1370Sschwartz 	IMU_PIC0_EVT_MASK,		/* IMU counter 0 */
59*1370Sschwartz 	IMU_PIC1_EVT_MASK,		/* IMU counter 1 */
60*1370Sschwartz 	MMU_PIC0_EVT_MASK,		/* MMU counter 0 */
61*1370Sschwartz 	MMU_PIC1_EVT_MASK,		/* MMU counter 1 */
62*1370Sschwartz 	TLU_PIC0_EVT_MASK,		/* TLU counter 0 */
63*1370Sschwartz 	TLU_PIC1_EVT_MASK,		/* TLU counter 1 */
64*1370Sschwartz 	TLU_PIC2_EVT_MASK,		/* TLU counter 2 */
65*1370Sschwartz 	LPU_PIC0_EVT_MASK,		/* LPU counter 1 */
66*1370Sschwartz 	LPU_PIC1_EVT_MASK		/* LPU counter 2 */
67*1370Sschwartz };
68*1370Sschwartz 
69*1370Sschwartz /* Offsets of the fields shown in event_field_masks. */
70*1370Sschwartz static int event_field_offset[NUM_TOTAL_COUNTERS] = {
71*1370Sschwartz 	PIC0_EVT_SEL_SHIFT,		/* JBC counter 0 */
72*1370Sschwartz 	PIC1_EVT_SEL_SHIFT,		/* JBC counter 1 */
73*1370Sschwartz 	PIC0_EVT_SEL_SHIFT,		/* IMU counter 0 */
74*1370Sschwartz 	PIC1_EVT_SEL_SHIFT,		/* IMU counter 1 */
75*1370Sschwartz 	PIC0_EVT_SEL_SHIFT,		/* MMU counter 0 */
76*1370Sschwartz 	PIC1_EVT_SEL_SHIFT,		/* MMU counter 1 */
77*1370Sschwartz 	PIC0_EVT_SEL_SHIFT,		/* TLU counter 0 */
78*1370Sschwartz 	PIC1_EVT_SEL_SHIFT,		/* TLU counter 1 */
79*1370Sschwartz 	PIC2_EVT_SEL_SHIFT,		/* TLU counter 2 */
80*1370Sschwartz 	PIC0_EVT_SEL_SHIFT,		/* LPU counter 1 */
81*1370Sschwartz 	PIC2_EVT_SEL_SHIFT		/* LPU counter 2 */
82*1370Sschwartz };
83*1370Sschwartz 
84*1370Sschwartz /*ARGSUSED*/
85*1370Sschwartz void
86*1370Sschwartz fpc_common_node_setup(dev_info_t *dip, int *index_p)
87*1370Sschwartz {
88*1370Sschwartz 	char pathname[MAXPATHLEN];
89*1370Sschwartz 
90*1370Sschwartz 	(void) ddi_pathname(dip, pathname);
91*1370Sschwartz 	node_data[this_node].name =
92*1370Sschwartz 	    kmem_zalloc(strlen(pathname)+1, KM_SLEEP);
93*1370Sschwartz 	(void) strcpy(node_data[this_node].name, pathname);
94*1370Sschwartz 	mutex_init(&node_data[this_node].mutex, NULL, MUTEX_DRIVER, NULL);
95*1370Sschwartz 	*index_p = this_node++;
96*1370Sschwartz }
97*1370Sschwartz 
98*1370Sschwartz int
99*1370Sschwartz fpc_perfcnt_module_init(dev_info_t *fpc_dip, int *avail)
100*1370Sschwartz {
101*1370Sschwartz 	int i;
102*1370Sschwartz 	dev_info_t *dip;
103*1370Sschwartz 
104*1370Sschwartz 	*avail = 0;
105*1370Sschwartz 
106*1370Sschwartz 	for (i = 1; i < MAX_REG_TYPES; i++) {
107*1370Sschwartz 		first_reg_of_type[i] =
108*1370Sschwartz 		    first_reg_of_type[i-1] + counters_per_type[i-1];
109*1370Sschwartz 	}
110*1370Sschwartz 
111*1370Sschwartz 	/*
112*1370Sschwartz 	 * Look thru first level of device tree only.
113*1370Sschwartz 	 * Assume there can be no more than NUM_LEAVES nodes in the system.
114*1370Sschwartz 	 */
115*1370Sschwartz 	dip = ddi_root_node();
116*1370Sschwartz 	for (dip = ddi_get_child(dip);
117*1370Sschwartz 	    ((dip != NULL) && (this_node < NUM_LEAVES));
118*1370Sschwartz 	    dip = ddi_get_next_sibling(dip)) {
119*1370Sschwartz 		if (fpc_platform_node_init(dip, avail) != SUCCESS)
120*1370Sschwartz 			return (DDI_FAILURE);
121*1370Sschwartz 	}
122*1370Sschwartz 
123*1370Sschwartz 	return ((*avail) ? fpc_platform_module_init(fpc_dip) : DDI_FAILURE);
124*1370Sschwartz }
125*1370Sschwartz 
126*1370Sschwartz int
127*1370Sschwartz fpc_perfcnt_module_fini(dev_info_t *dip)
128*1370Sschwartz {
129*1370Sschwartz 	int i;
130*1370Sschwartz 
131*1370Sschwartz 	for (i = 0; i < NUM_LEAVES; i++) {
132*1370Sschwartz 		fpc_platform_node_fini(node_data[i].plat_data_p);
133*1370Sschwartz 		if (node_data[i].name != NULL)
134*1370Sschwartz 			kmem_free(node_data[i].name,
135*1370Sschwartz 			    strlen(node_data[i].name) + 1);
136*1370Sschwartz 		mutex_destroy(&node_data[i].mutex);
137*1370Sschwartz 	}
138*1370Sschwartz 
139*1370Sschwartz 	fpc_platform_module_fini(dip);
140*1370Sschwartz 	return (DDI_SUCCESS);
141*1370Sschwartz }
142*1370Sschwartz 
143*1370Sschwartz char
144*1370Sschwartz *fpc_get_dev_name_by_number(int index)
145*1370Sschwartz {
146*1370Sschwartz 	return (node_data[index].name);
147*1370Sschwartz }
148*1370Sschwartz 
149*1370Sschwartz void *
150*1370Sschwartz fpc_get_platform_data_by_number(int index)
151*1370Sschwartz {
152*1370Sschwartz 	return (node_data[index].plat_data_p);
153*1370Sschwartz }
154*1370Sschwartz 
155*1370Sschwartz 
156*1370Sschwartz int
157*1370Sschwartz fpc_set_platform_data_by_number(int index, void *data_p)
158*1370Sschwartz {
159*1370Sschwartz 	node_data[index].plat_data_p = data_p;
160*1370Sschwartz 	return (SUCCESS);
161*1370Sschwartz }
162*1370Sschwartz 
163*1370Sschwartz 
164*1370Sschwartz static int
165*1370Sschwartz fpc_get_mutex_by_number(int index, kmutex_t **mutex_pp)
166*1370Sschwartz {
167*1370Sschwartz 	*mutex_pp = &node_data[index].mutex;
168*1370Sschwartz 	return (SUCCESS);
169*1370Sschwartz }
170*1370Sschwartz 
171*1370Sschwartz 
172*1370Sschwartz static int
173*1370Sschwartz fpc_get_counter_reg_index(fire_perfcnt_t regtype, int counter)
174*1370Sschwartz {
175*1370Sschwartz 	FPC_DBG1(
176*1370Sschwartz 	    "fpc_get_counter_reg_index: regtype:%d, counter:%d, bounds:%d\n",
177*1370Sschwartz 	    regtype, counter, counters_per_type[regtype]);
178*1370Sschwartz 	if (BOUNDS_CHECK_FAILS(counter, counters_per_type[regtype]))
179*1370Sschwartz 		return (-1);
180*1370Sschwartz 	FPC_DBG1("returning: %d\n", first_reg_of_type[regtype] + counter);
181*1370Sschwartz 	return (first_reg_of_type[regtype] + counter);
182*1370Sschwartz }
183*1370Sschwartz 
184*1370Sschwartz 
185*1370Sschwartz /*
186*1370Sschwartz  * Program a performance counter.
187*1370Sschwartz  *
188*1370Sschwartz  * reggroup is which type of counter.
189*1370Sschwartz  * counter is the counter number.
190*1370Sschwartz  * event is the event to program for that counter.
191*1370Sschwartz  */
192*1370Sschwartz int
193*1370Sschwartz fpc_perfcnt_program(int devnum, fire_perfcnt_t reggroup,
194*1370Sschwartz     uint64_t new_events)
195*1370Sschwartz {
196*1370Sschwartz 	int counter_index;
197*1370Sschwartz 	fire_perfreg_handle_t firehdl;
198*1370Sschwartz 	kmutex_t *mutex_p;
199*1370Sschwartz 	uint64_t old_events;
200*1370Sschwartz 	int rval = SUCCESS;
201*1370Sschwartz 	uint64_t zero = 0ull;
202*1370Sschwartz 	int num_counters, counter;
203*1370Sschwartz 
204*1370Sschwartz 	FPC_DBG1("fpc_perfcnt_program enter:\n");
205*1370Sschwartz 	FPC_DBG1("  devnum:%d, reggroup:%d, new_events:0x%" PRIx64 "\n",
206*1370Sschwartz 	    devnum, reggroup, new_events);
207*1370Sschwartz 
208*1370Sschwartz 	if ((firehdl = fpc_get_perfreg_handle(devnum)) ==
209*1370Sschwartz 	    (fire_perfreg_handle_t)-1)
210*1370Sschwartz 		return (EIO);
211*1370Sschwartz 
212*1370Sschwartz 	num_counters = counters_per_type[reggroup];
213*1370Sschwartz 
214*1370Sschwartz 	if (fpc_get_mutex_by_number(devnum, &mutex_p) != DDI_SUCCESS) {
215*1370Sschwartz 		(void) fpc_free_counter_handle(firehdl);
216*1370Sschwartz 		return (EIO);
217*1370Sschwartz 	}
218*1370Sschwartz 
219*1370Sschwartz 	mutex_enter(mutex_p);
220*1370Sschwartz 
221*1370Sschwartz 	if ((rval = fpc_event_io(firehdl, reggroup, &old_events, IS_READ)) !=
222*1370Sschwartz 	    SUCCESS) {
223*1370Sschwartz 		FPC_DBG1("Read of old event data failed, group:%d\n", reggroup);
224*1370Sschwartz 		goto done_pgm;
225*1370Sschwartz 	}
226*1370Sschwartz 
227*1370Sschwartz 	for (counter = 0; counter < num_counters; counter++) {
228*1370Sschwartz 
229*1370Sschwartz 		counter_index = fpc_get_counter_reg_index(reggroup, counter);
230*1370Sschwartz 
231*1370Sschwartz 		if ((old_events & event_field_mask[counter_index]) ==
232*1370Sschwartz 		    (new_events & event_field_mask[counter_index]))
233*1370Sschwartz 			continue;
234*1370Sschwartz 
235*1370Sschwartz 		FPC_DBG1("Zeroing counter %d\n", counter_index);
236*1370Sschwartz 		if ((rval = fpc_counter_io(firehdl, reggroup, counter_index,
237*1370Sschwartz 		    &zero, IS_WRITE)) != SUCCESS)
238*1370Sschwartz 			goto done_pgm;
239*1370Sschwartz 	}
240*1370Sschwartz 
241*1370Sschwartz 	if (old_events != new_events) {
242*1370Sschwartz 		if ((rval =
243*1370Sschwartz 		    fpc_event_io(firehdl, reggroup, &new_events, IS_WRITE)) !=
244*1370Sschwartz 		    SUCCESS) {
245*1370Sschwartz 			FPC_DBG1("Write of new event data failed, group:%d\n",
246*1370Sschwartz 			    reggroup);
247*1370Sschwartz 			goto done_pgm;
248*1370Sschwartz 		}
249*1370Sschwartz 	}
250*1370Sschwartz done_pgm:
251*1370Sschwartz 	mutex_exit(mutex_p);
252*1370Sschwartz 	(void) fpc_free_counter_handle(firehdl);
253*1370Sschwartz 	return (rval);
254*1370Sschwartz }
255*1370Sschwartz 
256*1370Sschwartz 
257*1370Sschwartz /*
258*1370Sschwartz  * Read a performance counter.
259*1370Sschwartz  *
260*1370Sschwartz  * reggroup is which type of counter.
261*1370Sschwartz  * event_p returns the event programmed for that counter.
262*1370Sschwartz  * values returns the counter values.
263*1370Sschwartz  */
264*1370Sschwartz int
265*1370Sschwartz fpc_perfcnt_read(int devnum, fire_perfcnt_t reggroup,
266*1370Sschwartz     uint64_t *event_p, uint64_t values[NUM_MAX_COUNTERS])
267*1370Sschwartz {
268*1370Sschwartz 	fire_perfreg_handle_t firehdl;
269*1370Sschwartz 	int counter_index;
270*1370Sschwartz 	kmutex_t *mutex_p;
271*1370Sschwartz 	int rval;
272*1370Sschwartz 	int num_counters, counter;
273*1370Sschwartz 
274*1370Sschwartz 	FPC_DBG1("fpc_perfcnt_read: devnum:%d\n", devnum);
275*1370Sschwartz 	num_counters = counters_per_type[reggroup];
276*1370Sschwartz 
277*1370Sschwartz 	if ((firehdl = fpc_get_perfreg_handle(devnum)) ==
278*1370Sschwartz 	    (fire_perfreg_handle_t)-1)
279*1370Sschwartz 		return (EIO);
280*1370Sschwartz 
281*1370Sschwartz 	if (fpc_get_mutex_by_number(devnum, &mutex_p) != DDI_SUCCESS)
282*1370Sschwartz 		return (EIO);
283*1370Sschwartz 
284*1370Sschwartz 	mutex_enter(mutex_p);
285*1370Sschwartz 
286*1370Sschwartz 	if ((rval = fpc_event_io(firehdl, reggroup, event_p, IS_READ)) !=
287*1370Sschwartz 	    SUCCESS)
288*1370Sschwartz 		goto done_read;
289*1370Sschwartz 
290*1370Sschwartz 	for (counter = 0; counter < num_counters; counter++) {
291*1370Sschwartz 		counter_index = fpc_get_counter_reg_index(reggroup, counter);
292*1370Sschwartz 
293*1370Sschwartz 		if ((rval = fpc_counter_io(firehdl, reggroup, counter_index,
294*1370Sschwartz 		    &values[counter], IS_READ)) != SUCCESS)
295*1370Sschwartz 			goto done_read;
296*1370Sschwartz 
297*1370Sschwartz 		FPC_DBG1("Read_counter %d / %d, status:%d, value returned:0x%"
298*1370Sschwartz 		    PRIx64 "\n", reggroup, counter, rval, values[counter]);
299*1370Sschwartz 	}
300*1370Sschwartz 
301*1370Sschwartz done_read:
302*1370Sschwartz 	mutex_exit(mutex_p);
303*1370Sschwartz 	(void) fpc_free_counter_handle(firehdl);
304*1370Sschwartz 	return (rval);
305*1370Sschwartz }
306