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