125cf1a30Sjl /*
225cf1a30Sjl  * CDDL HEADER START
325cf1a30Sjl  *
425cf1a30Sjl  * The contents of this file are subject to the terms of the
525cf1a30Sjl  * Common Development and Distribution License (the "License").
625cf1a30Sjl  * You may not use this file except in compliance with the License.
725cf1a30Sjl  *
825cf1a30Sjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
925cf1a30Sjl  * or http://www.opensolaris.org/os/licensing.
1025cf1a30Sjl  * See the License for the specific language governing permissions
1125cf1a30Sjl  * and limitations under the License.
1225cf1a30Sjl  *
1325cf1a30Sjl  * When distributing Covered Code, include this CDDL HEADER in each
1425cf1a30Sjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1525cf1a30Sjl  * If applicable, add the following below this CDDL HEADER, with the
1625cf1a30Sjl  * fields enclosed by brackets "[]" replaced with your own identifying
1725cf1a30Sjl  * information: Portions Copyright [yyyy] [name of copyright owner]
1825cf1a30Sjl  *
1925cf1a30Sjl  * CDDL HEADER END
2025cf1a30Sjl  */
2125cf1a30Sjl /*
2225cf1a30Sjl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
2325cf1a30Sjl  * Use is subject to license terms.
2425cf1a30Sjl  */
2525cf1a30Sjl 
2625cf1a30Sjl #include <sys/types.h>
2725cf1a30Sjl #include <sys/async.h>
2825cf1a30Sjl #include <sys/sunddi.h>
2925cf1a30Sjl #include <sys/sunndi.h>
3025cf1a30Sjl #include <sys/ddi_impldefs.h>
3125cf1a30Sjl #include <sys/pcicmu/pcicmu.h>
3225cf1a30Sjl #include <sys/machsystm.h>
3325cf1a30Sjl #include <sys/kstat.h>
3425cf1a30Sjl 
3525cf1a30Sjl static kstat_t *pcmu_create_picN_kstat(char *, int, int, int,
3625cf1a30Sjl 	pcmu_kev_mask_t *);
3725cf1a30Sjl 
3825cf1a30Sjl void
pcmu_kstat_create(pcmu_t * pcmu_p)3925cf1a30Sjl pcmu_kstat_create(pcmu_t *pcmu_p)
4025cf1a30Sjl {
4125cf1a30Sjl 	pcmu_add_upstream_kstat(pcmu_p);
4225cf1a30Sjl }
4325cf1a30Sjl 
4425cf1a30Sjl void
pcmu_kstat_destroy(pcmu_t * pcmu_p)4525cf1a30Sjl pcmu_kstat_destroy(pcmu_t *pcmu_p)
4625cf1a30Sjl {
4725cf1a30Sjl 	pcmu_rem_upstream_kstat(pcmu_p);
4825cf1a30Sjl }
4925cf1a30Sjl 
5025cf1a30Sjl void
pcmu_create_name_kstat(char * name,pcmu_ksinfo_t * pp,pcmu_kev_mask_t * ev)5125cf1a30Sjl pcmu_create_name_kstat(char *name, pcmu_ksinfo_t *pp, pcmu_kev_mask_t *ev)
5225cf1a30Sjl {
5325cf1a30Sjl 	int	i;
5425cf1a30Sjl 
5525cf1a30Sjl 	for (i = 0; i < NUM_OF_PICS; i++) {
5625cf1a30Sjl 		pp->pic_name_ksp[i] = pcmu_create_picN_kstat(name,
57*bbe1232eSToomas Soome 		    i, pp->pic_shift[i], pp->pic_no_evs, ev);
5825cf1a30Sjl 
5925cf1a30Sjl 		if (pp->pic_name_ksp[i] == NULL) {
6025cf1a30Sjl 			cmn_err(CE_WARN, "pci: unable to create name kstat");
6125cf1a30Sjl 		}
6225cf1a30Sjl 	}
6325cf1a30Sjl }
6425cf1a30Sjl 
6525cf1a30Sjl void
pcmu_delete_name_kstat(pcmu_ksinfo_t * pp)6625cf1a30Sjl pcmu_delete_name_kstat(pcmu_ksinfo_t *pp)
6725cf1a30Sjl {
6825cf1a30Sjl 	int	i;
6925cf1a30Sjl 
7025cf1a30Sjl 	if (pp == NULL) {
7125cf1a30Sjl 		return;
7225cf1a30Sjl 	}
7325cf1a30Sjl 	for (i = 0; i < NUM_OF_PICS; i++) {
7425cf1a30Sjl 		if (pp->pic_name_ksp[i] != NULL)
7525cf1a30Sjl 			kstat_delete(pp->pic_name_ksp[i]);
7625cf1a30Sjl 	}
7725cf1a30Sjl }
7825cf1a30Sjl 
7925cf1a30Sjl /*
8025cf1a30Sjl  * Create the picN kstat. Returns a pointer to the
8125cf1a30Sjl  * kstat which the driver must store to allow it
8225cf1a30Sjl  * to be deleted when necessary.
8325cf1a30Sjl  */
8425cf1a30Sjl static kstat_t *
pcmu_create_picN_kstat(char * mod_name,int pic,int pic_shift,int num_ev,pcmu_kev_mask_t * ev_array)8525cf1a30Sjl pcmu_create_picN_kstat(char *mod_name, int pic, int pic_shift,
86*bbe1232eSToomas Soome     int num_ev, pcmu_kev_mask_t *ev_array)
8725cf1a30Sjl {
8825cf1a30Sjl 	struct kstat_named *pic_named_data;
8925cf1a30Sjl 	int	inst = 0;
9025cf1a30Sjl 	int	event;
9125cf1a30Sjl 	char	pic_name[30];
9225cf1a30Sjl 	kstat_t	*picN_ksp = NULL;
9325cf1a30Sjl 
9425cf1a30Sjl 	(void) sprintf(pic_name, "pic%d", pic);
9525cf1a30Sjl 	if ((picN_ksp = kstat_create(mod_name, inst, pic_name,
96*bbe1232eSToomas Soome 	    "bus", KSTAT_TYPE_NAMED, num_ev, 0)) == NULL) {
9725cf1a30Sjl 		cmn_err(CE_WARN, "%s %s : kstat create failed",
98*bbe1232eSToomas Soome 		    mod_name, pic_name);
9925cf1a30Sjl 
10025cf1a30Sjl 		/*
10125cf1a30Sjl 		 * It is up to the calling function to delete any kstats
10225cf1a30Sjl 		 * that may have been created already. We just
10325cf1a30Sjl 		 * return NULL to indicate an error has occured.
10425cf1a30Sjl 		 */
10525cf1a30Sjl 		return (NULL);
10625cf1a30Sjl 	}
10725cf1a30Sjl 
10825cf1a30Sjl 	pic_named_data = (struct kstat_named *)picN_ksp->ks_data;
10925cf1a30Sjl 
11025cf1a30Sjl 	/*
11125cf1a30Sjl 	 * Write event names and their associated pcr masks. The
11225cf1a30Sjl 	 * last entry in the array (clear_pic) is added seperately
11325cf1a30Sjl 	 * below as the pic value must be inverted.
11425cf1a30Sjl 	 */
11525cf1a30Sjl 	for (event = 0; event < num_ev - 1; event++) {
11625cf1a30Sjl 		pic_named_data[event].value.ui64 =
11725cf1a30Sjl 		    (ev_array[event].pcr_mask << pic_shift);
11825cf1a30Sjl 
11925cf1a30Sjl 		kstat_named_init(&pic_named_data[event],
12025cf1a30Sjl 		    ev_array[event].event_name, KSTAT_DATA_UINT64);
12125cf1a30Sjl 	}
12225cf1a30Sjl 
12325cf1a30Sjl 	/*
12425cf1a30Sjl 	 * add the clear_pic entry.
12525cf1a30Sjl 	 */
12625cf1a30Sjl 	pic_named_data[event].value.ui64 =
12725cf1a30Sjl 	    (uint64_t)~(ev_array[event].pcr_mask << pic_shift);
12825cf1a30Sjl 
12925cf1a30Sjl 	kstat_named_init(&pic_named_data[event],
13025cf1a30Sjl 	    ev_array[event].event_name, KSTAT_DATA_UINT64);
13125cf1a30Sjl 
13225cf1a30Sjl 	kstat_install(picN_ksp);
13325cf1a30Sjl 	return (picN_ksp);
13425cf1a30Sjl }
13525cf1a30Sjl 
13625cf1a30Sjl /*
13725cf1a30Sjl  * Create the "counters" kstat.
13825cf1a30Sjl  */
pcmu_create_cntr_kstat(pcmu_t * pcmu_p,char * name,int num_pics,int (* update)(kstat_t *,int),void * cntr_addr_p)13925cf1a30Sjl kstat_t *pcmu_create_cntr_kstat(pcmu_t *pcmu_p, char *name,
14025cf1a30Sjl 	int num_pics, int (*update)(kstat_t *, int),
14125cf1a30Sjl 	void *cntr_addr_p)
14225cf1a30Sjl {
14325cf1a30Sjl 	struct kstat_named *counters_named_data;
14425cf1a30Sjl 	struct kstat	*counters_ksp;
14525cf1a30Sjl 	dev_info_t	*dip = pcmu_p->pcmu_dip;
14625cf1a30Sjl 	char		*drv_name = (char *)ddi_driver_name(dip);
14725cf1a30Sjl 	int		drv_instance = ddi_get_instance(dip);
14825cf1a30Sjl 	char		pic_str[10];
14925cf1a30Sjl 	int		i;
15025cf1a30Sjl 
15125cf1a30Sjl 	/*
15225cf1a30Sjl 	 * Size of kstat is num_pics + 1 as it
15325cf1a30Sjl 	 * also contains the %pcr
15425cf1a30Sjl 	 */
15525cf1a30Sjl 	if ((counters_ksp = kstat_create(name, drv_instance,
15625cf1a30Sjl 	    "counters", "bus", KSTAT_TYPE_NAMED, num_pics + 1,
15725cf1a30Sjl 	    KSTAT_FLAG_WRITABLE)) == NULL) {
15825cf1a30Sjl 		cmn_err(CE_WARN, "%s%d counters kstat_create failed",
159*bbe1232eSToomas Soome 		    drv_name, drv_instance);
16025cf1a30Sjl 		return (NULL);
16125cf1a30Sjl 	}
16225cf1a30Sjl 
16325cf1a30Sjl 	counters_named_data = (struct kstat_named *)(counters_ksp->ks_data);
16425cf1a30Sjl 
16525cf1a30Sjl 	/* initialize the named kstats */
16625cf1a30Sjl 	kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64);
16725cf1a30Sjl 
16825cf1a30Sjl 	for (i = 0; i < num_pics; i++) {
16925cf1a30Sjl 		(void) sprintf(pic_str, "pic%d", i);
17025cf1a30Sjl 		kstat_named_init(&counters_named_data[i+1],
17125cf1a30Sjl 		    pic_str, KSTAT_DATA_UINT64);
17225cf1a30Sjl 	}
17325cf1a30Sjl 
17425cf1a30Sjl 	/*
17525cf1a30Sjl 	 * Store the register offset's in the kstat's
17625cf1a30Sjl 	 * private field so that they are available
17725cf1a30Sjl 	 * to the update function.
17825cf1a30Sjl 	 */
17925cf1a30Sjl 	counters_ksp->ks_private = (void *)cntr_addr_p;
18025cf1a30Sjl 	counters_ksp->ks_update = update;
18125cf1a30Sjl 	kstat_install(counters_ksp);
18225cf1a30Sjl 	return (counters_ksp);
18325cf1a30Sjl }
18425cf1a30Sjl 
18525cf1a30Sjl /*
18625cf1a30Sjl  * kstat update function. Handles reads/writes
18725cf1a30Sjl  * from/to kstat.
18825cf1a30Sjl  */
18925cf1a30Sjl int
pcmu_cntr_kstat_update(kstat_t * ksp,int rw)19025cf1a30Sjl pcmu_cntr_kstat_update(kstat_t *ksp, int rw)
19125cf1a30Sjl {
19225cf1a30Sjl 	struct kstat_named	*data_p;
19325cf1a30Sjl 	pcmu_cntr_addr_t	*cntr_addr_p = ksp->ks_private;
19425cf1a30Sjl 	uint64_t	pic;
19525cf1a30Sjl 
19625cf1a30Sjl 	data_p = (struct kstat_named *)ksp->ks_data;
19725cf1a30Sjl 	if (rw == KSTAT_WRITE) {
19825cf1a30Sjl 		*cntr_addr_p->pcr_addr = data_p[0].value.ui64;
19925cf1a30Sjl 		return (0);
20025cf1a30Sjl 	} else {
20125cf1a30Sjl 		pic = *cntr_addr_p->pic_addr;
20225cf1a30Sjl 		data_p[0].value.ui64 = *cntr_addr_p->pcr_addr;
20325cf1a30Sjl 
20425cf1a30Sjl 		/* pic0 : lo 32 bits */
20525cf1a30Sjl 		data_p[1].value.ui64 = (pic <<32) >> 32;
20625cf1a30Sjl 		/* pic1 : hi 32 bits */
20725cf1a30Sjl 		data_p[2].value.ui64 = pic >> 32;
20825cf1a30Sjl 	}
20925cf1a30Sjl 	return (0);
21025cf1a30Sjl }
21125cf1a30Sjl 
21225cf1a30Sjl /*
21325cf1a30Sjl  * kstat update function using physical addresses.
21425cf1a30Sjl  */
21525cf1a30Sjl int
pcmu_cntr_kstat_pa_update(kstat_t * ksp,int rw)21625cf1a30Sjl pcmu_cntr_kstat_pa_update(kstat_t *ksp, int rw)
21725cf1a30Sjl {
21825cf1a30Sjl 	struct kstat_named	*data_p;
21925cf1a30Sjl 	pcmu_cntr_pa_t *cntr_pa_p = (pcmu_cntr_pa_t *)ksp->ks_private;
22025cf1a30Sjl 	uint64_t	pic;
22125cf1a30Sjl 
22225cf1a30Sjl 	data_p = (struct kstat_named *)ksp->ks_data;
22325cf1a30Sjl 
22425cf1a30Sjl 	if (rw == KSTAT_WRITE) {
22525cf1a30Sjl 		stdphysio(cntr_pa_p->pcr_pa, data_p[0].value.ui64);
22625cf1a30Sjl 		return (0);
22725cf1a30Sjl 	} else {
22825cf1a30Sjl 		pic = lddphysio(cntr_pa_p->pic_pa);
22925cf1a30Sjl 		data_p[0].value.ui64 = lddphysio(cntr_pa_p->pcr_pa);
23025cf1a30Sjl 
23125cf1a30Sjl 		/* pic0 : lo 32 bits */
23225cf1a30Sjl 		data_p[1].value.ui64 = (pic << 32) >> 32;
23325cf1a30Sjl 		/* pic1 : hi 32 bits */
23425cf1a30Sjl 		data_p[2].value.ui64 = pic >> 32;
23525cf1a30Sjl 	}
23625cf1a30Sjl 	return (0);
23725cf1a30Sjl }
23825cf1a30Sjl 
23925cf1a30Sjl 
24025cf1a30Sjl /*
24125cf1a30Sjl  * Matched with pcmu_add_upstream_kstat()
24225cf1a30Sjl  */
24325cf1a30Sjl void
pcmu_rem_upstream_kstat(pcmu_t * pcmu_p)24425cf1a30Sjl pcmu_rem_upstream_kstat(pcmu_t *pcmu_p)
24525cf1a30Sjl {
24625cf1a30Sjl 	if (pcmu_p->pcmu_uksp != NULL)
24725cf1a30Sjl 		kstat_delete(pcmu_p->pcmu_uksp);
24825cf1a30Sjl 	pcmu_p->pcmu_uksp = NULL;
24925cf1a30Sjl }
250