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