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