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