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 static kstat_t *pcmu_create_picN_kstat(char *, int, int, int,
38 pcmu_kev_mask_t *);
39
40 void
pcmu_kstat_create(pcmu_t * pcmu_p)41 pcmu_kstat_create(pcmu_t *pcmu_p)
42 {
43 pcmu_add_upstream_kstat(pcmu_p);
44 }
45
46 void
pcmu_kstat_destroy(pcmu_t * pcmu_p)47 pcmu_kstat_destroy(pcmu_t *pcmu_p)
48 {
49 pcmu_rem_upstream_kstat(pcmu_p);
50 }
51
52 void
pcmu_create_name_kstat(char * name,pcmu_ksinfo_t * pp,pcmu_kev_mask_t * ev)53 pcmu_create_name_kstat(char *name, pcmu_ksinfo_t *pp, pcmu_kev_mask_t *ev)
54 {
55 int i;
56
57 for (i = 0; i < NUM_OF_PICS; i++) {
58 pp->pic_name_ksp[i] = pcmu_create_picN_kstat(name,
59 i, pp->pic_shift[i], pp->pic_no_evs, ev);
60
61 if (pp->pic_name_ksp[i] == NULL) {
62 cmn_err(CE_WARN, "pci: unable to create name kstat");
63 }
64 }
65 }
66
67 void
pcmu_delete_name_kstat(pcmu_ksinfo_t * pp)68 pcmu_delete_name_kstat(pcmu_ksinfo_t *pp)
69 {
70 int i;
71
72 if (pp == NULL) {
73 return;
74 }
75 for (i = 0; i < NUM_OF_PICS; i++) {
76 if (pp->pic_name_ksp[i] != NULL)
77 kstat_delete(pp->pic_name_ksp[i]);
78 }
79 }
80
81 /*
82 * Create the picN kstat. Returns a pointer to the
83 * kstat which the driver must store to allow it
84 * to be deleted when necessary.
85 */
86 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 pcmu_create_picN_kstat(char *mod_name, int pic, int pic_shift,
88 int num_ev, pcmu_kev_mask_t *ev_array)
89 {
90 struct kstat_named *pic_named_data;
91 int inst = 0;
92 int event;
93 char pic_name[30];
94 kstat_t *picN_ksp = NULL;
95
96 (void) sprintf(pic_name, "pic%d", pic);
97 if ((picN_ksp = kstat_create(mod_name, inst, pic_name,
98 "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) {
99 cmn_err(CE_WARN, "%s %s : kstat create failed",
100 mod_name, pic_name);
101
102 /*
103 * It is up to the calling function to delete any kstats
104 * that may have been created already. We just
105 * return NULL to indicate an error has occured.
106 */
107 return (NULL);
108 }
109
110 pic_named_data = (struct kstat_named *)picN_ksp->ks_data;
111
112 /*
113 * Write event names and their associated pcr masks. The
114 * last entry in the array (clear_pic) is added seperately
115 * below as the pic value must be inverted.
116 */
117 for (event = 0; event < num_ev - 1; event++) {
118 pic_named_data[event].value.ui64 =
119 (ev_array[event].pcr_mask << pic_shift);
120
121 kstat_named_init(&pic_named_data[event],
122 ev_array[event].event_name, KSTAT_DATA_UINT64);
123 }
124
125 /*
126 * add the clear_pic entry.
127 */
128 pic_named_data[event].value.ui64 =
129 (uint64_t)~(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 kstat_install(picN_ksp);
135 return (picN_ksp);
136 }
137
138 /*
139 * Create the "counters" kstat.
140 */
pcmu_create_cntr_kstat(pcmu_t * pcmu_p,char * name,int num_pics,int (* update)(kstat_t *,int),void * cntr_addr_p)141 kstat_t *pcmu_create_cntr_kstat(pcmu_t *pcmu_p, char *name,
142 int num_pics, int (*update)(kstat_t *, int),
143 void *cntr_addr_p)
144 {
145 struct kstat_named *counters_named_data;
146 struct kstat *counters_ksp;
147 dev_info_t *dip = pcmu_p->pcmu_dip;
148 char *drv_name = (char *)ddi_driver_name(dip);
149 int drv_instance = ddi_get_instance(dip);
150 char pic_str[10];
151 int i;
152
153 /*
154 * Size of kstat is num_pics + 1 as it
155 * also contains the %pcr
156 */
157 if ((counters_ksp = kstat_create(name, drv_instance,
158 "counters", "bus", KSTAT_TYPE_NAMED, num_pics + 1,
159 KSTAT_FLAG_WRITABLE)) == NULL) {
160 cmn_err(CE_WARN, "%s%d counters kstat_create failed",
161 drv_name, drv_instance);
162 return (NULL);
163 }
164
165 counters_named_data = (struct kstat_named *)(counters_ksp->ks_data);
166
167 /* initialize the named kstats */
168 kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64);
169
170 for (i = 0; i < num_pics; i++) {
171 (void) sprintf(pic_str, "pic%d", i);
172 kstat_named_init(&counters_named_data[i+1],
173 pic_str, KSTAT_DATA_UINT64);
174 }
175
176 /*
177 * Store the register offset's in the kstat's
178 * private field so that they are available
179 * to the update function.
180 */
181 counters_ksp->ks_private = (void *)cntr_addr_p;
182 counters_ksp->ks_update = update;
183 kstat_install(counters_ksp);
184 return (counters_ksp);
185 }
186
187 /*
188 * kstat update function. Handles reads/writes
189 * from/to kstat.
190 */
191 int
pcmu_cntr_kstat_update(kstat_t * ksp,int rw)192 pcmu_cntr_kstat_update(kstat_t *ksp, int rw)
193 {
194 struct kstat_named *data_p;
195 pcmu_cntr_addr_t *cntr_addr_p = ksp->ks_private;
196 uint64_t pic;
197
198 data_p = (struct kstat_named *)ksp->ks_data;
199 if (rw == KSTAT_WRITE) {
200 *cntr_addr_p->pcr_addr = data_p[0].value.ui64;
201 return (0);
202 } else {
203 pic = *cntr_addr_p->pic_addr;
204 data_p[0].value.ui64 = *cntr_addr_p->pcr_addr;
205
206 /* pic0 : lo 32 bits */
207 data_p[1].value.ui64 = (pic <<32) >> 32;
208 /* pic1 : hi 32 bits */
209 data_p[2].value.ui64 = pic >> 32;
210 }
211 return (0);
212 }
213
214 /*
215 * kstat update function using physical addresses.
216 */
217 int
pcmu_cntr_kstat_pa_update(kstat_t * ksp,int rw)218 pcmu_cntr_kstat_pa_update(kstat_t *ksp, int rw)
219 {
220 struct kstat_named *data_p;
221 pcmu_cntr_pa_t *cntr_pa_p = (pcmu_cntr_pa_t *)ksp->ks_private;
222 uint64_t pic;
223
224 data_p = (struct kstat_named *)ksp->ks_data;
225
226 if (rw == KSTAT_WRITE) {
227 stdphysio(cntr_pa_p->pcr_pa, data_p[0].value.ui64);
228 return (0);
229 } else {
230 pic = lddphysio(cntr_pa_p->pic_pa);
231 data_p[0].value.ui64 = lddphysio(cntr_pa_p->pcr_pa);
232
233 /* pic0 : lo 32 bits */
234 data_p[1].value.ui64 = (pic << 32) >> 32;
235 /* pic1 : hi 32 bits */
236 data_p[2].value.ui64 = pic >> 32;
237 }
238 return (0);
239 }
240
241
242 /*
243 * Matched with pcmu_add_upstream_kstat()
244 */
245 void
pcmu_rem_upstream_kstat(pcmu_t * pcmu_p)246 pcmu_rem_upstream_kstat(pcmu_t *pcmu_p)
247 {
248 if (pcmu_p->pcmu_uksp != NULL)
249 kstat_delete(pcmu_p->pcmu_uksp);
250 pcmu_p->pcmu_uksp = NULL;
251 }
252