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