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