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
40static kstat_t *pci_create_picN_kstat(char *, int, int, int,
41	pci_kev_mask_t *);
42
43void
44pci_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
54void
55pci_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
65void
66pci_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
80void
81pci_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 */
98static kstat_t *
99pci_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 */
157kstat_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 */
214int
215pci_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 */
241int
242pci_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 */
269void
270pci_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