xref: /onnv-gate/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_counters.c (revision 2619:daf0055367bc)
1*1772Sjl139090 /*
2*1772Sjl139090  * CDDL HEADER START
3*1772Sjl139090  *
4*1772Sjl139090  * The contents of this file are subject to the terms of the
5*1772Sjl139090  * Common Development and Distribution License (the "License").
6*1772Sjl139090  * You may not use this file except in compliance with the License.
7*1772Sjl139090  *
8*1772Sjl139090  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1772Sjl139090  * or http://www.opensolaris.org/os/licensing.
10*1772Sjl139090  * See the License for the specific language governing permissions
11*1772Sjl139090  * and limitations under the License.
12*1772Sjl139090  *
13*1772Sjl139090  * When distributing Covered Code, include this CDDL HEADER in each
14*1772Sjl139090  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1772Sjl139090  * If applicable, add the following below this CDDL HEADER, with the
16*1772Sjl139090  * fields enclosed by brackets "[]" replaced with your own identifying
17*1772Sjl139090  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1772Sjl139090  *
19*1772Sjl139090  * CDDL HEADER END
20*1772Sjl139090  */
21*1772Sjl139090 /*
22*1772Sjl139090  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*1772Sjl139090  * Use is subject to license terms.
24*1772Sjl139090  */
25*1772Sjl139090 
26*1772Sjl139090 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*1772Sjl139090 
28*1772Sjl139090 #include <sys/types.h>
29*1772Sjl139090 #include <sys/async.h>
30*1772Sjl139090 #include <sys/sunddi.h>
31*1772Sjl139090 #include <sys/sunndi.h>
32*1772Sjl139090 #include <sys/ddi_impldefs.h>
33*1772Sjl139090 #include <sys/pcicmu/pcicmu.h>
34*1772Sjl139090 #include <sys/machsystm.h>
35*1772Sjl139090 #include <sys/kstat.h>
36*1772Sjl139090 
37*1772Sjl139090 static kstat_t *pcmu_create_picN_kstat(char *, int, int, int,
38*1772Sjl139090 	pcmu_kev_mask_t *);
39*1772Sjl139090 
40*1772Sjl139090 void
pcmu_kstat_create(pcmu_t * pcmu_p)41*1772Sjl139090 pcmu_kstat_create(pcmu_t *pcmu_p)
42*1772Sjl139090 {
43*1772Sjl139090 	pcmu_add_upstream_kstat(pcmu_p);
44*1772Sjl139090 }
45*1772Sjl139090 
46*1772Sjl139090 void
pcmu_kstat_destroy(pcmu_t * pcmu_p)47*1772Sjl139090 pcmu_kstat_destroy(pcmu_t *pcmu_p)
48*1772Sjl139090 {
49*1772Sjl139090 	pcmu_rem_upstream_kstat(pcmu_p);
50*1772Sjl139090 }
51*1772Sjl139090 
52*1772Sjl139090 void
pcmu_create_name_kstat(char * name,pcmu_ksinfo_t * pp,pcmu_kev_mask_t * ev)53*1772Sjl139090 pcmu_create_name_kstat(char *name, pcmu_ksinfo_t *pp, pcmu_kev_mask_t *ev)
54*1772Sjl139090 {
55*1772Sjl139090 	int	i;
56*1772Sjl139090 
57*1772Sjl139090 	for (i = 0; i < NUM_OF_PICS; i++) {
58*1772Sjl139090 		pp->pic_name_ksp[i] = pcmu_create_picN_kstat(name,
59*1772Sjl139090 			i, pp->pic_shift[i], pp->pic_no_evs, ev);
60*1772Sjl139090 
61*1772Sjl139090 		if (pp->pic_name_ksp[i] == NULL) {
62*1772Sjl139090 			cmn_err(CE_WARN, "pci: unable to create name kstat");
63*1772Sjl139090 		}
64*1772Sjl139090 	}
65*1772Sjl139090 }
66*1772Sjl139090 
67*1772Sjl139090 void
pcmu_delete_name_kstat(pcmu_ksinfo_t * pp)68*1772Sjl139090 pcmu_delete_name_kstat(pcmu_ksinfo_t *pp)
69*1772Sjl139090 {
70*1772Sjl139090 	int	i;
71*1772Sjl139090 
72*1772Sjl139090 	if (pp == NULL) {
73*1772Sjl139090 		return;
74*1772Sjl139090 	}
75*1772Sjl139090 	for (i = 0; i < NUM_OF_PICS; i++) {
76*1772Sjl139090 		if (pp->pic_name_ksp[i] != NULL)
77*1772Sjl139090 			kstat_delete(pp->pic_name_ksp[i]);
78*1772Sjl139090 	}
79*1772Sjl139090 }
80*1772Sjl139090 
81*1772Sjl139090 /*
82*1772Sjl139090  * Create the picN kstat. Returns a pointer to the
83*1772Sjl139090  * kstat which the driver must store to allow it
84*1772Sjl139090  * to be deleted when necessary.
85*1772Sjl139090  */
86*1772Sjl139090 static kstat_t *
pcmu_create_picN_kstat(char * mod_name,int pic,int pic_shift,int num_ev,pcmu_kev_mask_t * ev_array)87*1772Sjl139090 pcmu_create_picN_kstat(char *mod_name, int pic, int pic_shift,
88*1772Sjl139090 	int num_ev, pcmu_kev_mask_t *ev_array)
89*1772Sjl139090 {
90*1772Sjl139090 	struct kstat_named *pic_named_data;
91*1772Sjl139090 	int	inst = 0;
92*1772Sjl139090 	int	event;
93*1772Sjl139090 	char	pic_name[30];
94*1772Sjl139090 	kstat_t	*picN_ksp = NULL;
95*1772Sjl139090 
96*1772Sjl139090 	(void) sprintf(pic_name, "pic%d", pic);
97*1772Sjl139090 	if ((picN_ksp = kstat_create(mod_name, inst, pic_name,
98*1772Sjl139090 		"bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) {
99*1772Sjl139090 		cmn_err(CE_WARN, "%s %s : kstat create failed",
100*1772Sjl139090 			mod_name, pic_name);
101*1772Sjl139090 
102*1772Sjl139090 		/*
103*1772Sjl139090 		 * It is up to the calling function to delete any kstats
104*1772Sjl139090 		 * that may have been created already. We just
105*1772Sjl139090 		 * return NULL to indicate an error has occured.
106*1772Sjl139090 		 */
107*1772Sjl139090 		return (NULL);
108*1772Sjl139090 	}
109*1772Sjl139090 
110*1772Sjl139090 	pic_named_data = (struct kstat_named *)picN_ksp->ks_data;
111*1772Sjl139090 
112*1772Sjl139090 	/*
113*1772Sjl139090 	 * Write event names and their associated pcr masks. The
114*1772Sjl139090 	 * last entry in the array (clear_pic) is added seperately
115*1772Sjl139090 	 * below as the pic value must be inverted.
116*1772Sjl139090 	 */
117*1772Sjl139090 	for (event = 0; event < num_ev - 1; event++) {
118*1772Sjl139090 		pic_named_data[event].value.ui64 =
119*1772Sjl139090 		    (ev_array[event].pcr_mask << pic_shift);
120*1772Sjl139090 
121*1772Sjl139090 		kstat_named_init(&pic_named_data[event],
122*1772Sjl139090 		    ev_array[event].event_name, KSTAT_DATA_UINT64);
123*1772Sjl139090 	}
124*1772Sjl139090 
125*1772Sjl139090 	/*
126*1772Sjl139090 	 * add the clear_pic entry.
127*1772Sjl139090 	 */
128*1772Sjl139090 	pic_named_data[event].value.ui64 =
129*1772Sjl139090 	    (uint64_t)~(ev_array[event].pcr_mask << pic_shift);
130*1772Sjl139090 
131*1772Sjl139090 	kstat_named_init(&pic_named_data[event],
132*1772Sjl139090 	    ev_array[event].event_name, KSTAT_DATA_UINT64);
133*1772Sjl139090 
134*1772Sjl139090 	kstat_install(picN_ksp);
135*1772Sjl139090 	return (picN_ksp);
136*1772Sjl139090 }
137*1772Sjl139090 
138*1772Sjl139090 /*
139*1772Sjl139090  * Create the "counters" kstat.
140*1772Sjl139090  */
pcmu_create_cntr_kstat(pcmu_t * pcmu_p,char * name,int num_pics,int (* update)(kstat_t *,int),void * cntr_addr_p)141*1772Sjl139090 kstat_t *pcmu_create_cntr_kstat(pcmu_t *pcmu_p, char *name,
142*1772Sjl139090 	int num_pics, int (*update)(kstat_t *, int),
143*1772Sjl139090 	void *cntr_addr_p)
144*1772Sjl139090 {
145*1772Sjl139090 	struct kstat_named *counters_named_data;
146*1772Sjl139090 	struct kstat	*counters_ksp;
147*1772Sjl139090 	dev_info_t	*dip = pcmu_p->pcmu_dip;
148*1772Sjl139090 	char		*drv_name = (char *)ddi_driver_name(dip);
149*1772Sjl139090 	int		drv_instance = ddi_get_instance(dip);
150*1772Sjl139090 	char		pic_str[10];
151*1772Sjl139090 	int		i;
152*1772Sjl139090 
153*1772Sjl139090 	/*
154*1772Sjl139090 	 * Size of kstat is num_pics + 1 as it
155*1772Sjl139090 	 * also contains the %pcr
156*1772Sjl139090 	 */
157*1772Sjl139090 	if ((counters_ksp = kstat_create(name, drv_instance,
158*1772Sjl139090 	    "counters", "bus", KSTAT_TYPE_NAMED, num_pics + 1,
159*1772Sjl139090 	    KSTAT_FLAG_WRITABLE)) == NULL) {
160*1772Sjl139090 		cmn_err(CE_WARN, "%s%d counters kstat_create failed",
161*1772Sjl139090 			drv_name, drv_instance);
162*1772Sjl139090 		return (NULL);
163*1772Sjl139090 	}
164*1772Sjl139090 
165*1772Sjl139090 	counters_named_data = (struct kstat_named *)(counters_ksp->ks_data);
166*1772Sjl139090 
167*1772Sjl139090 	/* initialize the named kstats */
168*1772Sjl139090 	kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64);
169*1772Sjl139090 
170*1772Sjl139090 	for (i = 0; i < num_pics; i++) {
171*1772Sjl139090 		(void) sprintf(pic_str, "pic%d", i);
172*1772Sjl139090 		kstat_named_init(&counters_named_data[i+1],
173*1772Sjl139090 		    pic_str, KSTAT_DATA_UINT64);
174*1772Sjl139090 	}
175*1772Sjl139090 
176*1772Sjl139090 	/*
177*1772Sjl139090 	 * Store the register offset's in the kstat's
178*1772Sjl139090 	 * private field so that they are available
179*1772Sjl139090 	 * to the update function.
180*1772Sjl139090 	 */
181*1772Sjl139090 	counters_ksp->ks_private = (void *)cntr_addr_p;
182*1772Sjl139090 	counters_ksp->ks_update = update;
183*1772Sjl139090 	kstat_install(counters_ksp);
184*1772Sjl139090 	return (counters_ksp);
185*1772Sjl139090 }
186*1772Sjl139090 
187*1772Sjl139090 /*
188*1772Sjl139090  * kstat update function. Handles reads/writes
189*1772Sjl139090  * from/to kstat.
190*1772Sjl139090  */
191*1772Sjl139090 int
pcmu_cntr_kstat_update(kstat_t * ksp,int rw)192*1772Sjl139090 pcmu_cntr_kstat_update(kstat_t *ksp, int rw)
193*1772Sjl139090 {
194*1772Sjl139090 	struct kstat_named	*data_p;
195*1772Sjl139090 	pcmu_cntr_addr_t	*cntr_addr_p = ksp->ks_private;
196*1772Sjl139090 	uint64_t	pic;
197*1772Sjl139090 
198*1772Sjl139090 	data_p = (struct kstat_named *)ksp->ks_data;
199*1772Sjl139090 	if (rw == KSTAT_WRITE) {
200*1772Sjl139090 		*cntr_addr_p->pcr_addr = data_p[0].value.ui64;
201*1772Sjl139090 		return (0);
202*1772Sjl139090 	} else {
203*1772Sjl139090 		pic = *cntr_addr_p->pic_addr;
204*1772Sjl139090 		data_p[0].value.ui64 = *cntr_addr_p->pcr_addr;
205*1772Sjl139090 
206*1772Sjl139090 		/* pic0 : lo 32 bits */
207*1772Sjl139090 		data_p[1].value.ui64 = (pic <<32) >> 32;
208*1772Sjl139090 		/* pic1 : hi 32 bits */
209*1772Sjl139090 		data_p[2].value.ui64 = pic >> 32;
210*1772Sjl139090 	}
211*1772Sjl139090 	return (0);
212*1772Sjl139090 }
213*1772Sjl139090 
214*1772Sjl139090 /*
215*1772Sjl139090  * kstat update function using physical addresses.
216*1772Sjl139090  */
217*1772Sjl139090 int
pcmu_cntr_kstat_pa_update(kstat_t * ksp,int rw)218*1772Sjl139090 pcmu_cntr_kstat_pa_update(kstat_t *ksp, int rw)
219*1772Sjl139090 {
220*1772Sjl139090 	struct kstat_named	*data_p;
221*1772Sjl139090 	pcmu_cntr_pa_t *cntr_pa_p = (pcmu_cntr_pa_t *)ksp->ks_private;
222*1772Sjl139090 	uint64_t	pic;
223*1772Sjl139090 
224*1772Sjl139090 	data_p = (struct kstat_named *)ksp->ks_data;
225*1772Sjl139090 
226*1772Sjl139090 	if (rw == KSTAT_WRITE) {
227*1772Sjl139090 		stdphysio(cntr_pa_p->pcr_pa, data_p[0].value.ui64);
228*1772Sjl139090 		return (0);
229*1772Sjl139090 	} else {
230*1772Sjl139090 		pic = lddphysio(cntr_pa_p->pic_pa);
231*1772Sjl139090 		data_p[0].value.ui64 = lddphysio(cntr_pa_p->pcr_pa);
232*1772Sjl139090 
233*1772Sjl139090 		/* pic0 : lo 32 bits */
234*1772Sjl139090 		data_p[1].value.ui64 = (pic << 32) >> 32;
235*1772Sjl139090 		/* pic1 : hi 32 bits */
236*1772Sjl139090 		data_p[2].value.ui64 = pic >> 32;
237*1772Sjl139090 	}
238*1772Sjl139090 	return (0);
239*1772Sjl139090 }
240*1772Sjl139090 
241*1772Sjl139090 
242*1772Sjl139090 /*
243*1772Sjl139090  * Matched with pcmu_add_upstream_kstat()
244*1772Sjl139090  */
245*1772Sjl139090 void
pcmu_rem_upstream_kstat(pcmu_t * pcmu_p)246*1772Sjl139090 pcmu_rem_upstream_kstat(pcmu_t *pcmu_p)
247*1772Sjl139090 {
248*1772Sjl139090 	if (pcmu_p->pcmu_uksp != NULL)
249*1772Sjl139090 		kstat_delete(pcmu_p->pcmu_uksp);
250*1772Sjl139090 	pcmu_p->pcmu_uksp = NULL;
251*1772Sjl139090 }
252