xref: /onnv-gate/usr/src/uts/common/io/ib/adapters/hermon/hermon_stats.c (revision 11190:a4ba02130229)
19517SBill.Taylor@Sun.COM /*
29517SBill.Taylor@Sun.COM  * CDDL HEADER START
39517SBill.Taylor@Sun.COM  *
49517SBill.Taylor@Sun.COM  * The contents of this file are subject to the terms of the
59517SBill.Taylor@Sun.COM  * Common Development and Distribution License (the "License").
69517SBill.Taylor@Sun.COM  * You may not use this file except in compliance with the License.
79517SBill.Taylor@Sun.COM  *
89517SBill.Taylor@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99517SBill.Taylor@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109517SBill.Taylor@Sun.COM  * See the License for the specific language governing permissions
119517SBill.Taylor@Sun.COM  * and limitations under the License.
129517SBill.Taylor@Sun.COM  *
139517SBill.Taylor@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149517SBill.Taylor@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159517SBill.Taylor@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169517SBill.Taylor@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179517SBill.Taylor@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189517SBill.Taylor@Sun.COM  *
199517SBill.Taylor@Sun.COM  * CDDL HEADER END
209517SBill.Taylor@Sun.COM  */
219517SBill.Taylor@Sun.COM 
229517SBill.Taylor@Sun.COM /*
239517SBill.Taylor@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
249517SBill.Taylor@Sun.COM  * Use is subject to license terms.
259517SBill.Taylor@Sun.COM  */
269517SBill.Taylor@Sun.COM 
279517SBill.Taylor@Sun.COM /*
289517SBill.Taylor@Sun.COM  * hermon_stats.c
299517SBill.Taylor@Sun.COM  *    Hermon IB Performance Statistics routines
309517SBill.Taylor@Sun.COM  *
319517SBill.Taylor@Sun.COM  *    Implements all the routines necessary for setting up, querying, and
329517SBill.Taylor@Sun.COM  *    (later) tearing down all the kstats necessary for implementing to
339517SBill.Taylor@Sun.COM  *    the interfaces necessary to provide busstat(1M) access.
349517SBill.Taylor@Sun.COM  */
359517SBill.Taylor@Sun.COM 
369517SBill.Taylor@Sun.COM #include <sys/types.h>
379517SBill.Taylor@Sun.COM #include <sys/conf.h>
389517SBill.Taylor@Sun.COM #include <sys/ddi.h>
399517SBill.Taylor@Sun.COM #include <sys/sunddi.h>
409517SBill.Taylor@Sun.COM #include <sys/modctl.h>
419517SBill.Taylor@Sun.COM 
429517SBill.Taylor@Sun.COM #include <sys/ib/adapters/hermon/hermon.h>
439517SBill.Taylor@Sun.COM 
449517SBill.Taylor@Sun.COM static kstat_t *hermon_kstat_picN_create(hermon_state_t *state, int num_pic,
459517SBill.Taylor@Sun.COM     int num_evt, hermon_ks_mask_t *ev_array);
469517SBill.Taylor@Sun.COM static kstat_t *hermon_kstat_cntr_create(hermon_state_t *state, int num_pic,
479517SBill.Taylor@Sun.COM     int (*update)(kstat_t *, int));
489517SBill.Taylor@Sun.COM static int hermon_kstat_cntr_update(kstat_t *ksp, int rw);
499517SBill.Taylor@Sun.COM 
509879SRamaswamy.Tummala@Sun.COM void hermon_kstat_perfcntr64_create(hermon_state_t *state, uint_t port_num);
519879SRamaswamy.Tummala@Sun.COM static int hermon_kstat_perfcntr64_read(hermon_state_t *state, uint_t port,
529879SRamaswamy.Tummala@Sun.COM     int reset);
539879SRamaswamy.Tummala@Sun.COM static void hermon_kstat_perfcntr64_thread_exit(hermon_ks_info_t *ksi);
549879SRamaswamy.Tummala@Sun.COM static int hermon_kstat_perfcntr64_update(kstat_t *ksp, int rw);
559879SRamaswamy.Tummala@Sun.COM 
569517SBill.Taylor@Sun.COM /*
579517SBill.Taylor@Sun.COM  * Hermon IB Performance Events structure
589517SBill.Taylor@Sun.COM  *    This structure is read-only and is used to setup the individual kstats
599517SBill.Taylor@Sun.COM  *    and to initialize the tki_ib_perfcnt[] array for each Hermon instance.
609517SBill.Taylor@Sun.COM  */
619517SBill.Taylor@Sun.COM hermon_ks_mask_t hermon_ib_perfcnt_list[HERMON_CNTR_NUMENTRIES] = {
629517SBill.Taylor@Sun.COM 	{"port_xmit_data", 0, 0},
639517SBill.Taylor@Sun.COM 	{"port_recv_data", 0, 0},
649517SBill.Taylor@Sun.COM 	{"port_xmit_pkts", 0, 0},
659517SBill.Taylor@Sun.COM 	{"port_recv_pkts", 0, 0},
669517SBill.Taylor@Sun.COM 	{"port_recv_err", 0, 0},
679517SBill.Taylor@Sun.COM 	{"port_xmit_discards", 0, 0},
689517SBill.Taylor@Sun.COM 	{"vl15_dropped", 0, 0},
699517SBill.Taylor@Sun.COM 	{"port_xmit_wait", 0, 0},
709517SBill.Taylor@Sun.COM 	{"port_recv_remote_phys_err", 0, 0},
719517SBill.Taylor@Sun.COM 	{"port_xmit_constraint_err", 0, 0},
729517SBill.Taylor@Sun.COM 	{"port_recv_constraint_err", 0, 0},
739517SBill.Taylor@Sun.COM 	{"symbol_err_counter", 0, 0},
749517SBill.Taylor@Sun.COM 	{"link_err_recovery_cnt", 0, 0},
759517SBill.Taylor@Sun.COM 	{"link_downed_cnt", 0, 0},
769517SBill.Taylor@Sun.COM 	{"excessive_buffer_overruns", 0, 0},
779517SBill.Taylor@Sun.COM 	{"local_link_integrity_err", 0, 0},
789517SBill.Taylor@Sun.COM 	{"clear_pic", 0, 0}
799517SBill.Taylor@Sun.COM };
809517SBill.Taylor@Sun.COM 
819879SRamaswamy.Tummala@Sun.COM /*
829879SRamaswamy.Tummala@Sun.COM  * Return the maximum of (x) and (y)
839879SRamaswamy.Tummala@Sun.COM  */
849879SRamaswamy.Tummala@Sun.COM #define	MAX(x, y)	(((x) > (y)) ? (x) : (y))
859879SRamaswamy.Tummala@Sun.COM 
869879SRamaswamy.Tummala@Sun.COM /*
879879SRamaswamy.Tummala@Sun.COM  * Set (x) to the maximum of (x) and (y)
889879SRamaswamy.Tummala@Sun.COM  */
899879SRamaswamy.Tummala@Sun.COM #define	SET_TO_MAX(x, y)	\
909879SRamaswamy.Tummala@Sun.COM {				\
919879SRamaswamy.Tummala@Sun.COM 	if ((x) < (y))		\
929879SRamaswamy.Tummala@Sun.COM 		(x) = (y);	\
939879SRamaswamy.Tummala@Sun.COM }
949517SBill.Taylor@Sun.COM 
959517SBill.Taylor@Sun.COM /*
969517SBill.Taylor@Sun.COM  * hermon_kstat_init()
979517SBill.Taylor@Sun.COM  *    Context: Only called from attach() path context
989517SBill.Taylor@Sun.COM  */
999517SBill.Taylor@Sun.COM int
hermon_kstat_init(hermon_state_t * state)1009517SBill.Taylor@Sun.COM hermon_kstat_init(hermon_state_t *state)
1019517SBill.Taylor@Sun.COM {
1029517SBill.Taylor@Sun.COM 	hermon_ks_info_t		*ksi;
1039517SBill.Taylor@Sun.COM 	uint_t			numports;
1049517SBill.Taylor@Sun.COM 	int			i;
1059517SBill.Taylor@Sun.COM 
1069517SBill.Taylor@Sun.COM 	/* Allocate a kstat info structure */
1079517SBill.Taylor@Sun.COM 	ksi = (hermon_ks_info_t *)kmem_zalloc(sizeof (hermon_ks_info_t),
1089517SBill.Taylor@Sun.COM 	    KM_SLEEP);
1099517SBill.Taylor@Sun.COM 	if (ksi == NULL) {
1109517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
1119517SBill.Taylor@Sun.COM 	}
1129517SBill.Taylor@Sun.COM 	state->hs_ks_info = ksi;
1139517SBill.Taylor@Sun.COM 
1149517SBill.Taylor@Sun.COM 	/*
1159879SRamaswamy.Tummala@Sun.COM 	 * Create as many "pic" and perfcntr64 kstats as we have IB ports.
1169879SRamaswamy.Tummala@Sun.COM 	 * Enable all of the events specified in the "hermon_ib_perfcnt_list"
1179879SRamaswamy.Tummala@Sun.COM 	 * structure.
1189517SBill.Taylor@Sun.COM 	 */
1199517SBill.Taylor@Sun.COM 	numports = state->hs_cfg_profile->cp_num_ports;
1209517SBill.Taylor@Sun.COM 	for (i = 0; i < numports; i++) {
1219517SBill.Taylor@Sun.COM 		ksi->hki_picN_ksp[i] = hermon_kstat_picN_create(state, i,
1229517SBill.Taylor@Sun.COM 		    HERMON_CNTR_NUMENTRIES, hermon_ib_perfcnt_list);
1239517SBill.Taylor@Sun.COM 		if (ksi->hki_picN_ksp[i] == NULL) {
1249517SBill.Taylor@Sun.COM 			goto kstat_init_fail;
1259517SBill.Taylor@Sun.COM 		}
1269879SRamaswamy.Tummala@Sun.COM 
1279879SRamaswamy.Tummala@Sun.COM 		hermon_kstat_perfcntr64_create(state, i + 1);
1289879SRamaswamy.Tummala@Sun.COM 		if (ksi->hki_perfcntr64[i].hki64_ksp == NULL) {
1299879SRamaswamy.Tummala@Sun.COM 			goto kstat_init_fail;
1309879SRamaswamy.Tummala@Sun.COM 		}
1319517SBill.Taylor@Sun.COM 	}
1329517SBill.Taylor@Sun.COM 
1339517SBill.Taylor@Sun.COM 	/* Create the "counters" kstat too */
1349517SBill.Taylor@Sun.COM 	ksi->hki_cntr_ksp = hermon_kstat_cntr_create(state, numports,
1359517SBill.Taylor@Sun.COM 	    hermon_kstat_cntr_update);
1369517SBill.Taylor@Sun.COM 	if (ksi->hki_cntr_ksp == NULL) {
1379517SBill.Taylor@Sun.COM 		goto kstat_init_fail;
1389517SBill.Taylor@Sun.COM 	}
1399517SBill.Taylor@Sun.COM 
1409517SBill.Taylor@Sun.COM 	/* Initialize the control register and initial counter values */
1419517SBill.Taylor@Sun.COM 	ksi->hki_pcr  = 0;
1429517SBill.Taylor@Sun.COM 	ksi->hki_pic0 = 0;
1439517SBill.Taylor@Sun.COM 	ksi->hki_pic1 = 0;
1449517SBill.Taylor@Sun.COM 
1459517SBill.Taylor@Sun.COM 	/*
1469517SBill.Taylor@Sun.COM 	 * Initialize the Hermon hki_ib_perfcnt[] array values using the
1479517SBill.Taylor@Sun.COM 	 * default values in hermon_ib_perfcnt_list[]
1489517SBill.Taylor@Sun.COM 	 */
1499517SBill.Taylor@Sun.COM 	for (i = 0; i < HERMON_CNTR_NUMENTRIES; i++) {
1509517SBill.Taylor@Sun.COM 		ksi->hki_ib_perfcnt[i] = hermon_ib_perfcnt_list[i];
1519517SBill.Taylor@Sun.COM 	}
1529517SBill.Taylor@Sun.COM 
1539879SRamaswamy.Tummala@Sun.COM 	mutex_init(&ksi->hki_perfcntr64_lock, NULL, MUTEX_DRIVER, NULL);
1549879SRamaswamy.Tummala@Sun.COM 	cv_init(&ksi->hki_perfcntr64_cv, NULL, CV_DRIVER, NULL);
1559879SRamaswamy.Tummala@Sun.COM 
1569517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
1579517SBill.Taylor@Sun.COM 
1589517SBill.Taylor@Sun.COM 
1599517SBill.Taylor@Sun.COM kstat_init_fail:
1609517SBill.Taylor@Sun.COM 
1619517SBill.Taylor@Sun.COM 	/* Delete all the previously created kstats */
1629517SBill.Taylor@Sun.COM 	if (ksi->hki_cntr_ksp != NULL) {
1639517SBill.Taylor@Sun.COM 		kstat_delete(ksi->hki_cntr_ksp);
1649517SBill.Taylor@Sun.COM 	}
1659517SBill.Taylor@Sun.COM 	for (i = 0; i < numports; i++) {
1669517SBill.Taylor@Sun.COM 		if (ksi->hki_picN_ksp[i] != NULL) {
1679517SBill.Taylor@Sun.COM 			kstat_delete(ksi->hki_picN_ksp[i]);
1689517SBill.Taylor@Sun.COM 		}
1699879SRamaswamy.Tummala@Sun.COM 		if (ksi->hki_perfcntr64[i].hki64_ksp != NULL) {
1709879SRamaswamy.Tummala@Sun.COM 			kstat_delete(ksi->hki_perfcntr64[i].hki64_ksp);
1719879SRamaswamy.Tummala@Sun.COM 		}
1729517SBill.Taylor@Sun.COM 	}
1739517SBill.Taylor@Sun.COM 
1749517SBill.Taylor@Sun.COM 	/* Free the kstat info structure */
1759517SBill.Taylor@Sun.COM 	kmem_free(ksi, sizeof (hermon_ks_info_t));
1769517SBill.Taylor@Sun.COM 
1779517SBill.Taylor@Sun.COM 	return (DDI_FAILURE);
1789517SBill.Taylor@Sun.COM }
1799517SBill.Taylor@Sun.COM 
1809517SBill.Taylor@Sun.COM 
1819517SBill.Taylor@Sun.COM /*
1829517SBill.Taylor@Sun.COM  * hermon_kstat_init()
1839517SBill.Taylor@Sun.COM  *    Context: Only called from attach() and/or detach() path contexts
1849517SBill.Taylor@Sun.COM  */
1859517SBill.Taylor@Sun.COM void
hermon_kstat_fini(hermon_state_t * state)1869517SBill.Taylor@Sun.COM hermon_kstat_fini(hermon_state_t *state)
1879517SBill.Taylor@Sun.COM {
1889879SRamaswamy.Tummala@Sun.COM 	hermon_ks_info_t	*ksi;
1899517SBill.Taylor@Sun.COM 	uint_t			numports;
1909517SBill.Taylor@Sun.COM 	int			i;
1919517SBill.Taylor@Sun.COM 
1929517SBill.Taylor@Sun.COM 	/* Get pointer to kstat info */
1939517SBill.Taylor@Sun.COM 	ksi = state->hs_ks_info;
1949517SBill.Taylor@Sun.COM 
1959879SRamaswamy.Tummala@Sun.COM 	/*
1969879SRamaswamy.Tummala@Sun.COM 	 * Signal the perfcntr64_update_thread to exit and wait until the
1979879SRamaswamy.Tummala@Sun.COM 	 * thread exits.
1989879SRamaswamy.Tummala@Sun.COM 	 */
1999879SRamaswamy.Tummala@Sun.COM 	mutex_enter(&ksi->hki_perfcntr64_lock);
2009879SRamaswamy.Tummala@Sun.COM 	hermon_kstat_perfcntr64_thread_exit(ksi);
2019879SRamaswamy.Tummala@Sun.COM 	mutex_exit(&ksi->hki_perfcntr64_lock);
2029879SRamaswamy.Tummala@Sun.COM 
2039879SRamaswamy.Tummala@Sun.COM 	/* Delete all the "pic" and perfcntr64 kstats (one per port) */
2049517SBill.Taylor@Sun.COM 	numports = state->hs_cfg_profile->cp_num_ports;
2059517SBill.Taylor@Sun.COM 	for (i = 0; i < numports; i++) {
2069517SBill.Taylor@Sun.COM 		if (ksi->hki_picN_ksp[i] != NULL) {
2079517SBill.Taylor@Sun.COM 			kstat_delete(ksi->hki_picN_ksp[i]);
2089517SBill.Taylor@Sun.COM 		}
2099879SRamaswamy.Tummala@Sun.COM 
2109879SRamaswamy.Tummala@Sun.COM 		if (ksi->hki_perfcntr64[i].hki64_ksp != NULL) {
2119879SRamaswamy.Tummala@Sun.COM 			kstat_delete(ksi->hki_perfcntr64[i].hki64_ksp);
2129879SRamaswamy.Tummala@Sun.COM 		}
2139517SBill.Taylor@Sun.COM 	}
2149517SBill.Taylor@Sun.COM 
2159517SBill.Taylor@Sun.COM 	/* Delete the "counter" kstats (one per port) */
2169517SBill.Taylor@Sun.COM 	kstat_delete(ksi->hki_cntr_ksp);
2179517SBill.Taylor@Sun.COM 
2189879SRamaswamy.Tummala@Sun.COM 	cv_destroy(&ksi->hki_perfcntr64_cv);
2199879SRamaswamy.Tummala@Sun.COM 	mutex_destroy(&ksi->hki_perfcntr64_lock);
2209879SRamaswamy.Tummala@Sun.COM 
2219517SBill.Taylor@Sun.COM 	/* Free the kstat info structure */
2229517SBill.Taylor@Sun.COM 	kmem_free(ksi, sizeof (hermon_ks_info_t));
2239517SBill.Taylor@Sun.COM }
2249517SBill.Taylor@Sun.COM 
2259517SBill.Taylor@Sun.COM 
2269517SBill.Taylor@Sun.COM /*
2279517SBill.Taylor@Sun.COM  * hermon_kstat_picN_create()
2289517SBill.Taylor@Sun.COM  *    Context: Only called from attach() path context
2299517SBill.Taylor@Sun.COM  */
2309517SBill.Taylor@Sun.COM static kstat_t *
hermon_kstat_picN_create(hermon_state_t * state,int num_pic,int num_evt,hermon_ks_mask_t * ev_array)2319517SBill.Taylor@Sun.COM hermon_kstat_picN_create(hermon_state_t *state, int num_pic, int num_evt,
2329517SBill.Taylor@Sun.COM     hermon_ks_mask_t *ev_array)
2339517SBill.Taylor@Sun.COM {
2349517SBill.Taylor@Sun.COM 	kstat_t			*picN_ksp;
2359517SBill.Taylor@Sun.COM 	struct kstat_named	*pic_named_data;
2369517SBill.Taylor@Sun.COM 	int			drv_instance, i;
2379517SBill.Taylor@Sun.COM 	char			*drv_name;
2389517SBill.Taylor@Sun.COM 	char			pic_name[16];
2399517SBill.Taylor@Sun.COM 
2409517SBill.Taylor@Sun.COM 	/*
2419517SBill.Taylor@Sun.COM 	 * Create the "picN" kstat.  In the steps, below we will attach
2429517SBill.Taylor@Sun.COM 	 * all of our named event types to it.
2439517SBill.Taylor@Sun.COM 	 */
2449517SBill.Taylor@Sun.COM 	drv_name = (char *)ddi_driver_name(state->hs_dip);
2459517SBill.Taylor@Sun.COM 	drv_instance = ddi_get_instance(state->hs_dip);
2469517SBill.Taylor@Sun.COM 	(void) sprintf(pic_name, "pic%d", num_pic);
2479517SBill.Taylor@Sun.COM 	picN_ksp = kstat_create(drv_name, drv_instance, pic_name, "bus",
2489517SBill.Taylor@Sun.COM 	    KSTAT_TYPE_NAMED, num_evt, NULL);
2499517SBill.Taylor@Sun.COM 	if (picN_ksp == NULL) {
2509517SBill.Taylor@Sun.COM 		return (NULL);
2519517SBill.Taylor@Sun.COM 	}
2529517SBill.Taylor@Sun.COM 	pic_named_data = (struct kstat_named *)(picN_ksp->ks_data);
2539517SBill.Taylor@Sun.COM 
2549517SBill.Taylor@Sun.COM 	/*
2559517SBill.Taylor@Sun.COM 	 * Write event names and their associated pcr masks. The last entry
2569517SBill.Taylor@Sun.COM 	 * in the array (clear_pic) is added separately below (as its pic
2579517SBill.Taylor@Sun.COM 	 * value must be inverted).
2589517SBill.Taylor@Sun.COM 	 */
2599517SBill.Taylor@Sun.COM 	for (i = 0; i < num_evt - 1; i++) {
2609517SBill.Taylor@Sun.COM 		pic_named_data[i].value.ui64 =
2619517SBill.Taylor@Sun.COM 		    ((uint64_t)i << (num_pic * HERMON_CNTR_SIZE));
2629517SBill.Taylor@Sun.COM 		kstat_named_init(&pic_named_data[i], ev_array[i].ks_evt_name,
2639517SBill.Taylor@Sun.COM 		    KSTAT_DATA_UINT64);
2649517SBill.Taylor@Sun.COM 	}
2659517SBill.Taylor@Sun.COM 
2669517SBill.Taylor@Sun.COM 	/* Add the "clear_pic" entry */
2679517SBill.Taylor@Sun.COM 	pic_named_data[i].value.ui64 =
2689517SBill.Taylor@Sun.COM 	    ~((uint64_t)HERMON_CNTR_MASK << (num_pic * HERMON_CNTR_SIZE));
2699517SBill.Taylor@Sun.COM 	kstat_named_init(&pic_named_data[i], ev_array[i].ks_evt_name,
2709517SBill.Taylor@Sun.COM 	    KSTAT_DATA_UINT64);
2719517SBill.Taylor@Sun.COM 
2729517SBill.Taylor@Sun.COM 	/* Install the kstat */
2739517SBill.Taylor@Sun.COM 	kstat_install(picN_ksp);
2749517SBill.Taylor@Sun.COM 
2759517SBill.Taylor@Sun.COM 	return (picN_ksp);
2769517SBill.Taylor@Sun.COM }
2779517SBill.Taylor@Sun.COM 
2789517SBill.Taylor@Sun.COM 
2799517SBill.Taylor@Sun.COM /*
2809517SBill.Taylor@Sun.COM  * hermon_kstat_cntr_create()
2819517SBill.Taylor@Sun.COM  *    Context: Only called from attach() path context
2829517SBill.Taylor@Sun.COM  */
2839517SBill.Taylor@Sun.COM static kstat_t *
hermon_kstat_cntr_create(hermon_state_t * state,int num_pic,int (* update)(kstat_t *,int))2849517SBill.Taylor@Sun.COM hermon_kstat_cntr_create(hermon_state_t *state, int num_pic,
2859517SBill.Taylor@Sun.COM     int (*update)(kstat_t *, int))
2869517SBill.Taylor@Sun.COM {
2879517SBill.Taylor@Sun.COM 	struct kstat		*cntr_ksp;
2889517SBill.Taylor@Sun.COM 	struct kstat_named	*cntr_named_data;
2899517SBill.Taylor@Sun.COM 	int			drv_instance, i;
2909517SBill.Taylor@Sun.COM 	char			*drv_name;
2919517SBill.Taylor@Sun.COM 	char			pic_str[16];
2929517SBill.Taylor@Sun.COM 
2939517SBill.Taylor@Sun.COM 	/*
2949517SBill.Taylor@Sun.COM 	 * Create the "counters" kstat.  In the steps, below we will attach
2959517SBill.Taylor@Sun.COM 	 * all of our "pic" to it.   Note:  The size of this kstat is
2969517SBill.Taylor@Sun.COM 	 * num_pic + 1 because it also contains the "%pcr".
2979517SBill.Taylor@Sun.COM 	 */
2989517SBill.Taylor@Sun.COM 	drv_name = (char *)ddi_driver_name(state->hs_dip);
2999517SBill.Taylor@Sun.COM 	drv_instance = ddi_get_instance(state->hs_dip);
3009517SBill.Taylor@Sun.COM 	cntr_ksp = kstat_create(drv_name, drv_instance, "counters", "bus",
3019517SBill.Taylor@Sun.COM 	    KSTAT_TYPE_NAMED, num_pic + 1, KSTAT_FLAG_WRITABLE);
3029517SBill.Taylor@Sun.COM 	if (cntr_ksp == NULL) {
3039517SBill.Taylor@Sun.COM 		return (NULL);
3049517SBill.Taylor@Sun.COM 	}
3059517SBill.Taylor@Sun.COM 	cntr_named_data = (struct kstat_named *)(cntr_ksp->ks_data);
3069517SBill.Taylor@Sun.COM 
3079517SBill.Taylor@Sun.COM 	/*
3089517SBill.Taylor@Sun.COM 	 * Initialize the named kstats (for the "pcr" and for the
3099517SBill.Taylor@Sun.COM 	 * individual "pic" kstats)
3109517SBill.Taylor@Sun.COM 	 */
3119517SBill.Taylor@Sun.COM 	kstat_named_init(&cntr_named_data[0], "pcr", KSTAT_DATA_UINT64);
3129517SBill.Taylor@Sun.COM 	for (i = 0; i < num_pic; i++) {
3139517SBill.Taylor@Sun.COM 		(void) sprintf(pic_str, "pic%d", i);
3149517SBill.Taylor@Sun.COM 		kstat_named_init(&cntr_named_data[i+1], pic_str,
3159517SBill.Taylor@Sun.COM 		    KSTAT_DATA_UINT64);
3169517SBill.Taylor@Sun.COM 	}
3179517SBill.Taylor@Sun.COM 
3189517SBill.Taylor@Sun.COM 	/*
3199517SBill.Taylor@Sun.COM 	 * Store the Hermon softstate pointer in the kstat's private field so
3209517SBill.Taylor@Sun.COM 	 * that it is available to the update function.
3219517SBill.Taylor@Sun.COM 	 */
3229517SBill.Taylor@Sun.COM 	cntr_ksp->ks_private = (void *)state;
3239517SBill.Taylor@Sun.COM 	cntr_ksp->ks_update  = update;
3249517SBill.Taylor@Sun.COM 
3259517SBill.Taylor@Sun.COM 	/* Install the kstat */
3269517SBill.Taylor@Sun.COM 	kstat_install(cntr_ksp);
3279517SBill.Taylor@Sun.COM 
3289517SBill.Taylor@Sun.COM 	return (cntr_ksp);
3299517SBill.Taylor@Sun.COM }
3309517SBill.Taylor@Sun.COM 
3319517SBill.Taylor@Sun.COM 
3329517SBill.Taylor@Sun.COM /*
3339517SBill.Taylor@Sun.COM  * hermon_kstat_cntr_update()
3349517SBill.Taylor@Sun.COM  *    Context: Called from the kstat context
3359517SBill.Taylor@Sun.COM  */
3369517SBill.Taylor@Sun.COM static int
hermon_kstat_cntr_update(kstat_t * ksp,int rw)3379517SBill.Taylor@Sun.COM hermon_kstat_cntr_update(kstat_t *ksp, int rw)
3389517SBill.Taylor@Sun.COM {
3399517SBill.Taylor@Sun.COM 	hermon_state_t		*state;
3409517SBill.Taylor@Sun.COM 	hermon_ks_mask_t		*ib_perf;
3419517SBill.Taylor@Sun.COM 	hermon_ks_info_t		*ksi;
3429517SBill.Taylor@Sun.COM 	struct kstat_named	*data;
3439517SBill.Taylor@Sun.COM 	uint64_t		pcr;
3449517SBill.Taylor@Sun.COM 	uint32_t		tmp;
3459517SBill.Taylor@Sun.COM 	uint32_t		oldval;
3469517SBill.Taylor@Sun.COM 	uint_t			numports, indx;
3479517SBill.Taylor@Sun.COM 	int			status;
3489517SBill.Taylor@Sun.COM 	hermon_hw_sm_perfcntr_t	sm_perfcntr;
3499517SBill.Taylor@Sun.COM 
3509517SBill.Taylor@Sun.COM 	/*
3519517SBill.Taylor@Sun.COM 	 * Extract the Hermon softstate pointer, kstat data, pointer to the
3529517SBill.Taylor@Sun.COM 	 * kstat info structure, and pointer to the hki_ib_perfcnt[] array
3539517SBill.Taylor@Sun.COM 	 * from the input parameters.  Note: For warlock purposes, these
3549517SBill.Taylor@Sun.COM 	 * parameters are all accessed only in this routine and are,
3559517SBill.Taylor@Sun.COM 	 * therefore, protected by the lock used by the kstat framework.
3569517SBill.Taylor@Sun.COM 	 */
3579517SBill.Taylor@Sun.COM 	state	= ksp->ks_private;
3589517SBill.Taylor@Sun.COM 	data	= (struct kstat_named *)(ksp->ks_data);
3599517SBill.Taylor@Sun.COM 	ksi	= state->hs_ks_info;
3609517SBill.Taylor@Sun.COM 	ib_perf = &ksi->hki_ib_perfcnt[0];
3619517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ksi))
3629517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
3639517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ib_perf))
3649517SBill.Taylor@Sun.COM 
3659517SBill.Taylor@Sun.COM 	/*
3669517SBill.Taylor@Sun.COM 	 * Depending on whether we are reading the "pic" counters or
3679517SBill.Taylor@Sun.COM 	 * writing the "pcr" control register, we need to handle and
3689517SBill.Taylor@Sun.COM 	 * fill in the kstat data appropriately.
3699517SBill.Taylor@Sun.COM 	 *
3709517SBill.Taylor@Sun.COM 	 * If this is a write to the "pcr", then extract the value from
3719517SBill.Taylor@Sun.COM 	 * the kstat data and store it in the kstat info structure.
3729517SBill.Taylor@Sun.COM 	 *
3739517SBill.Taylor@Sun.COM 	 * Otherwise, if this is a read of the "pic" counter(s), then
3749517SBill.Taylor@Sun.COM 	 * extract the register offset, size, and mask values from the
3759517SBill.Taylor@Sun.COM 	 * ib_perf[] array.  Then read the corresponding register and store
3769517SBill.Taylor@Sun.COM 	 * it into the kstat data.  Note:  We only read/fill in pic1 if more
3779517SBill.Taylor@Sun.COM 	 * than one port is configured.
3789517SBill.Taylor@Sun.COM 	 */
3799517SBill.Taylor@Sun.COM 	numports = state->hs_cfg_profile->cp_num_ports;
3809517SBill.Taylor@Sun.COM 	if (rw == KSTAT_WRITE) {
3819517SBill.Taylor@Sun.COM 		/* Update the stored "pcr" value */
3829517SBill.Taylor@Sun.COM 		ksi->hki_pcr = data[0].value.ui64;
3839517SBill.Taylor@Sun.COM 		return (0);
3849517SBill.Taylor@Sun.COM 	} else {
3859517SBill.Taylor@Sun.COM 		/*
3869517SBill.Taylor@Sun.COM 		 * Get the current "pcr" value and extract the lower
3879517SBill.Taylor@Sun.COM 		 * portion (corresponding to the counters for "pic0")
3889517SBill.Taylor@Sun.COM 		 */
3899517SBill.Taylor@Sun.COM 		pcr  = ksi->hki_pcr;
3909517SBill.Taylor@Sun.COM 		indx = pcr & HERMON_CNTR_MASK;
3919517SBill.Taylor@Sun.COM 		data[0].value.ui64 = pcr;
3929517SBill.Taylor@Sun.COM 
3939517SBill.Taylor@Sun.COM 		/*
3949517SBill.Taylor@Sun.COM 		 * Fill in the "pic0" counter, corresponding to port 1.
3959517SBill.Taylor@Sun.COM 		 * This involves reading in the current value in the register
3969517SBill.Taylor@Sun.COM 		 * and calculating how many events have happened since this
3979517SBill.Taylor@Sun.COM 		 * register was last polled.  Then we save away the current
3989517SBill.Taylor@Sun.COM 		 * value for the counter and increment the "pic0" total by
3999517SBill.Taylor@Sun.COM 		 * the number of new events.
4009517SBill.Taylor@Sun.COM 		 */
4019517SBill.Taylor@Sun.COM 		oldval = ib_perf[indx].ks_old_pic0;
4029517SBill.Taylor@Sun.COM 
4039517SBill.Taylor@Sun.COM 		status = hermon_getperfcntr_cmd_post(state, 1,
4049879SRamaswamy.Tummala@Sun.COM 		    HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
4059517SBill.Taylor@Sun.COM 		if (status != HERMON_CMD_SUCCESS) {
4069517SBill.Taylor@Sun.COM 			return (-1);
4079517SBill.Taylor@Sun.COM 		}
4089517SBill.Taylor@Sun.COM 		switch (indx) {
4099517SBill.Taylor@Sun.COM 		case 0:		/* port_xmit_data */
4109517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.portxmdata;
4119517SBill.Taylor@Sun.COM 			break;
4129517SBill.Taylor@Sun.COM 		case 1:		/* port_recv_data */
4139517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.portrcdata;
4149517SBill.Taylor@Sun.COM 			break;
4159517SBill.Taylor@Sun.COM 		case 2:		/* port_xmit_pkts */
4169517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.portxmpkts;
4179517SBill.Taylor@Sun.COM 			break;
4189517SBill.Taylor@Sun.COM 		case 3:		/* port_recv_pkts */
4199517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.portrcpkts;
4209517SBill.Taylor@Sun.COM 			break;
4219517SBill.Taylor@Sun.COM 		case 4:		/* port_recv_err */
4229517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.portrcv;
4239517SBill.Taylor@Sun.COM 			break;
4249517SBill.Taylor@Sun.COM 		case 5:		/* port_xmit_discards */
4259517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.portxmdiscard;
4269517SBill.Taylor@Sun.COM 			break;
4279517SBill.Taylor@Sun.COM 		case 6:		/* vl15_dropped */
4289517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.vl15drop;
4299517SBill.Taylor@Sun.COM 			break;
4309517SBill.Taylor@Sun.COM 		case 7:		/* port_xmit_wait */
4319517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.portxmwait;
4329517SBill.Taylor@Sun.COM 			break;
4339517SBill.Taylor@Sun.COM 		case 8:		/* port_recv_remote_phys_err */
4349517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.portrcvrem;
4359517SBill.Taylor@Sun.COM 			break;
4369517SBill.Taylor@Sun.COM 		case 9:		/* port_xmit_constraint_err */
4379517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.portxmconstr;
4389517SBill.Taylor@Sun.COM 			break;
4399517SBill.Taylor@Sun.COM 		case 10:	/* port_recv_constraint_err */
4409517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.portrcconstr;
4419517SBill.Taylor@Sun.COM 			break;
4429517SBill.Taylor@Sun.COM 		case 11:	/* symbol_err_counter */
4439517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.symerr;
4449517SBill.Taylor@Sun.COM 			break;
4459517SBill.Taylor@Sun.COM 		case 12:	/* link_err_recovery_cnt */
4469517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.linkerrrec;
4479517SBill.Taylor@Sun.COM 			break;
4489517SBill.Taylor@Sun.COM 		case 13:	/* link_downed_cnt */
4499517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.linkdown;
4509517SBill.Taylor@Sun.COM 			break;
4519517SBill.Taylor@Sun.COM 		case 14:	/* excessive_buffer_overruns */
4529517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.xsbuffovrun;
4539517SBill.Taylor@Sun.COM 			break;
4549517SBill.Taylor@Sun.COM 		case 15:	/* local_link_integrity_err */
4559517SBill.Taylor@Sun.COM 			tmp = sm_perfcntr.locallinkint;
4569517SBill.Taylor@Sun.COM 			break;
4579517SBill.Taylor@Sun.COM 		case 16:	/* clear_pic */
4589517SBill.Taylor@Sun.COM 			tmp = 0;	/* XXX */
4599517SBill.Taylor@Sun.COM 			break;
4609517SBill.Taylor@Sun.COM 		default:
4619517SBill.Taylor@Sun.COM 			cmn_err(CE_CONT, "perf counter out of range\n");
4629517SBill.Taylor@Sun.COM 		}
4639517SBill.Taylor@Sun.COM 
4649517SBill.Taylor@Sun.COM 		ib_perf[indx].ks_old_pic0 = tmp;
4659517SBill.Taylor@Sun.COM 
4669517SBill.Taylor@Sun.COM 		tmp = tmp - oldval;
4679517SBill.Taylor@Sun.COM 		ksi->hki_pic0 += tmp;
4689517SBill.Taylor@Sun.COM 		data[1].value.ui64 = ksi->hki_pic0;
4699517SBill.Taylor@Sun.COM 
4709517SBill.Taylor@Sun.COM 		/*
4719517SBill.Taylor@Sun.COM 		 * If necessary, fill in the "pic1" counter for port 2.
4729517SBill.Taylor@Sun.COM 		 * This works the same as above except that we extract the
4739517SBill.Taylor@Sun.COM 		 * upper bits (corresponding to the counters for "pic1")
4749517SBill.Taylor@Sun.COM 		 */
4759517SBill.Taylor@Sun.COM 		if (numports == HERMON_MAX_PORTS) {
4769517SBill.Taylor@Sun.COM 			indx   = pcr >> HERMON_CNTR_SIZE;
4779517SBill.Taylor@Sun.COM 			oldval = ib_perf[indx].ks_old_pic1;
4789517SBill.Taylor@Sun.COM 
4799517SBill.Taylor@Sun.COM 			status = hermon_getperfcntr_cmd_post(state, 2,
4809879SRamaswamy.Tummala@Sun.COM 			    HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
4819517SBill.Taylor@Sun.COM 			if (status != HERMON_CMD_SUCCESS) {
4829517SBill.Taylor@Sun.COM 				return (-1);
4839517SBill.Taylor@Sun.COM 			}
4849517SBill.Taylor@Sun.COM 			switch (indx) {
4859517SBill.Taylor@Sun.COM 			case 0:		/* port_xmit_data */
4869517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.portxmdata;
4879517SBill.Taylor@Sun.COM 				break;
4889517SBill.Taylor@Sun.COM 			case 1:		/* port_recv_data */
4899517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.portrcdata;
4909517SBill.Taylor@Sun.COM 				break;
4919517SBill.Taylor@Sun.COM 			case 2:		/* port_xmit_pkts */
4929517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.portxmpkts;
4939517SBill.Taylor@Sun.COM 				break;
4949517SBill.Taylor@Sun.COM 			case 3:		/* port_recv_pkts */
4959517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.portrcpkts;
4969517SBill.Taylor@Sun.COM 				break;
4979517SBill.Taylor@Sun.COM 			case 4:		/* port_recv_err */
4989517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.portrcv;
4999517SBill.Taylor@Sun.COM 				break;
5009517SBill.Taylor@Sun.COM 			case 5:		/* port_xmit_discards */
5019517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.portxmdiscard;
5029517SBill.Taylor@Sun.COM 				break;
5039517SBill.Taylor@Sun.COM 			case 6:		/* vl15_dropped */
5049517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.vl15drop;
5059517SBill.Taylor@Sun.COM 				break;
5069517SBill.Taylor@Sun.COM 			case 7:		/* port_xmit_wait */
5079517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.portxmwait;
5089517SBill.Taylor@Sun.COM 				break;
5099517SBill.Taylor@Sun.COM 			case 8:		/* port_recv_remote_phys_err */
5109517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.portrcvrem;
5119517SBill.Taylor@Sun.COM 				break;
5129517SBill.Taylor@Sun.COM 			case 9:		/* port_xmit_constraint_err */
5139517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.portxmconstr;
5149517SBill.Taylor@Sun.COM 				break;
5159517SBill.Taylor@Sun.COM 			case 10:	/* port_recv_constraint_err */
5169517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.portrcconstr;
5179517SBill.Taylor@Sun.COM 				break;
5189517SBill.Taylor@Sun.COM 			case 11:	/* symbol_err_counter */
5199517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.symerr;
5209517SBill.Taylor@Sun.COM 				break;
5219517SBill.Taylor@Sun.COM 			case 12:	/* link_err_recovery_cnt */
5229517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.linkerrrec;
5239517SBill.Taylor@Sun.COM 				break;
5249517SBill.Taylor@Sun.COM 			case 13:	/* link_downed_cnt */
5259517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.linkdown;
5269517SBill.Taylor@Sun.COM 				break;
5279517SBill.Taylor@Sun.COM 			case 14:	/* excessive_buffer_overruns */
5289517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.xsbuffovrun;
5299517SBill.Taylor@Sun.COM 				break;
5309517SBill.Taylor@Sun.COM 			case 15:	/* local_link_integrity_err */
5319517SBill.Taylor@Sun.COM 				tmp = sm_perfcntr.locallinkint;
5329517SBill.Taylor@Sun.COM 				break;
5339517SBill.Taylor@Sun.COM 			case 16:	/* clear_pic */
5349517SBill.Taylor@Sun.COM 				tmp = 0;	/* XXX */
5359517SBill.Taylor@Sun.COM 				break;
5369517SBill.Taylor@Sun.COM 			default:
5379517SBill.Taylor@Sun.COM 				cmn_err(CE_CONT, "perf counter out of range\n");
5389517SBill.Taylor@Sun.COM 			}
5399517SBill.Taylor@Sun.COM 
5409517SBill.Taylor@Sun.COM 			ib_perf[indx].ks_old_pic1 = tmp;
5419517SBill.Taylor@Sun.COM 
5429517SBill.Taylor@Sun.COM 			tmp = tmp - oldval;
5439517SBill.Taylor@Sun.COM 			ksi->hki_pic1 += tmp;
5449517SBill.Taylor@Sun.COM 			data[2].value.ui64 = ksi->hki_pic1;
5459517SBill.Taylor@Sun.COM 		}
5469517SBill.Taylor@Sun.COM 
5479517SBill.Taylor@Sun.COM 		return (0);
5489517SBill.Taylor@Sun.COM 	}
5499517SBill.Taylor@Sun.COM }
5509879SRamaswamy.Tummala@Sun.COM 
5519879SRamaswamy.Tummala@Sun.COM /*
5529879SRamaswamy.Tummala@Sun.COM  * 64 bit kstats for performance counters:
5539879SRamaswamy.Tummala@Sun.COM  *
554*11190SRamaswamy.Tummala@Sun.COM  * Export 64 bit performance counters in kstats.
555*11190SRamaswamy.Tummala@Sun.COM  *
556*11190SRamaswamy.Tummala@Sun.COM  * If the HCA hardware supports 64 bit extended port counters, we use the
557*11190SRamaswamy.Tummala@Sun.COM  * hardware based counters. If the HCA hardware does not support extended port
558*11190SRamaswamy.Tummala@Sun.COM  * counters, we maintain 64 bit performance counters in software using the
559*11190SRamaswamy.Tummala@Sun.COM  * 32 bit hardware port counters.
560*11190SRamaswamy.Tummala@Sun.COM  *
561*11190SRamaswamy.Tummala@Sun.COM  * The software based counters are maintained as follows:
5629879SRamaswamy.Tummala@Sun.COM  *
5639879SRamaswamy.Tummala@Sun.COM  * We create a thread that, every one second, reads the values of 32 bit
5649879SRamaswamy.Tummala@Sun.COM  * hardware counters and adds them to the 64 bit software counters. Immediately
5659879SRamaswamy.Tummala@Sun.COM  * after reading, it resets the 32 bit hardware counters to zero (so that they
5669879SRamaswamy.Tummala@Sun.COM  * start counting from zero again). At any time the current value of a counter
5679879SRamaswamy.Tummala@Sun.COM  * is going to be the sum of the 64 bit software counter and the 32 bit
5689879SRamaswamy.Tummala@Sun.COM  * hardware counter.
5699879SRamaswamy.Tummala@Sun.COM  *
5709879SRamaswamy.Tummala@Sun.COM  * Since this work need not be done if there is no consumer, by default
5719879SRamaswamy.Tummala@Sun.COM  * we do not maintain 64 bit software counters. To enable this the consumer
5729879SRamaswamy.Tummala@Sun.COM  * needs to write a non-zero value to the "enable" component of the of
5739879SRamaswamy.Tummala@Sun.COM  * perf_counters kstat. Writing zero to this component will disable this work.
574*11190SRamaswamy.Tummala@Sun.COM  * NOTE: The enabling or disabling applies to software based counters only.
575*11190SRamaswamy.Tummala@Sun.COM  * Hardware based counters counters are always enabled.
5769879SRamaswamy.Tummala@Sun.COM  *
5779879SRamaswamy.Tummala@Sun.COM  * If performance monitor is enabled in subnet manager, the SM could
5789879SRamaswamy.Tummala@Sun.COM  * periodically reset the hardware counters by sending perf-MADs. So only
5799879SRamaswamy.Tummala@Sun.COM  * one of either our software 64 bit counters or the SM performance monitor
5809879SRamaswamy.Tummala@Sun.COM  * could be enabled at the same time. However, if both of them are enabled at
5819879SRamaswamy.Tummala@Sun.COM  * the same time we still do our best by keeping track of the values of the
5829879SRamaswamy.Tummala@Sun.COM  * last read 32 bit hardware counters. If the current read of a 32 bit hardware
5839879SRamaswamy.Tummala@Sun.COM  * counter is less than the last read of the counter, we ignore the current
5849879SRamaswamy.Tummala@Sun.COM  * value and go with the last read value.
5859879SRamaswamy.Tummala@Sun.COM  */
5869879SRamaswamy.Tummala@Sun.COM 
5879879SRamaswamy.Tummala@Sun.COM /*
5889879SRamaswamy.Tummala@Sun.COM  * hermon_kstat_perfcntr64_create()
5899879SRamaswamy.Tummala@Sun.COM  *    Context: Only called from attach() path context
5909879SRamaswamy.Tummala@Sun.COM  *
5919879SRamaswamy.Tummala@Sun.COM  * Create "port#/perf_counters" kstat for the specified port number.
5929879SRamaswamy.Tummala@Sun.COM  */
5939879SRamaswamy.Tummala@Sun.COM void
hermon_kstat_perfcntr64_create(hermon_state_t * state,uint_t port_num)5949879SRamaswamy.Tummala@Sun.COM hermon_kstat_perfcntr64_create(hermon_state_t *state, uint_t port_num)
5959879SRamaswamy.Tummala@Sun.COM {
5969879SRamaswamy.Tummala@Sun.COM 	hermon_ks_info_t	*ksi = state->hs_ks_info;
5979879SRamaswamy.Tummala@Sun.COM 	struct kstat		*cntr_ksp;
5989879SRamaswamy.Tummala@Sun.COM 	struct kstat_named	*cntr_named_data;
5999879SRamaswamy.Tummala@Sun.COM 	int			drv_instance;
6009879SRamaswamy.Tummala@Sun.COM 	char			*drv_name;
6019879SRamaswamy.Tummala@Sun.COM 	char			kname[32];
602*11190SRamaswamy.Tummala@Sun.COM 	int			status, ext_width_supported;
6039879SRamaswamy.Tummala@Sun.COM 
6049879SRamaswamy.Tummala@Sun.COM 	ASSERT(port_num != 0);
6059879SRamaswamy.Tummala@Sun.COM 
606*11190SRamaswamy.Tummala@Sun.COM 	status = hermon_is_ext_port_counters_supported(state, port_num,
607*11190SRamaswamy.Tummala@Sun.COM 	    HERMON_CMD_NOSLEEP_SPIN, &ext_width_supported);
608*11190SRamaswamy.Tummala@Sun.COM 	if (status == HERMON_CMD_SUCCESS) {
609*11190SRamaswamy.Tummala@Sun.COM 		ksi->hki_perfcntr64[port_num - 1].
610*11190SRamaswamy.Tummala@Sun.COM 		    hki64_ext_port_counters_supported = ext_width_supported;
611*11190SRamaswamy.Tummala@Sun.COM 	}
612*11190SRamaswamy.Tummala@Sun.COM 
6139879SRamaswamy.Tummala@Sun.COM 	drv_name = (char *)ddi_driver_name(state->hs_dip);
6149879SRamaswamy.Tummala@Sun.COM 	drv_instance = ddi_get_instance(state->hs_dip);
6159879SRamaswamy.Tummala@Sun.COM 	(void) snprintf(kname, sizeof (kname), "port%u/perf_counters",
6169879SRamaswamy.Tummala@Sun.COM 	    port_num);
6179879SRamaswamy.Tummala@Sun.COM 	cntr_ksp = kstat_create(drv_name, drv_instance, kname, "ib",
6189879SRamaswamy.Tummala@Sun.COM 	    KSTAT_TYPE_NAMED, HERMON_PERFCNTR64_NUM_COUNTERS,
6199879SRamaswamy.Tummala@Sun.COM 	    KSTAT_FLAG_WRITABLE);
6209879SRamaswamy.Tummala@Sun.COM 	if (cntr_ksp == NULL) {
6219879SRamaswamy.Tummala@Sun.COM 		return;
6229879SRamaswamy.Tummala@Sun.COM 	}
6239879SRamaswamy.Tummala@Sun.COM 	cntr_named_data = (struct kstat_named *)(cntr_ksp->ks_data);
6249879SRamaswamy.Tummala@Sun.COM 
6259879SRamaswamy.Tummala@Sun.COM 	kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_ENABLE_IDX],
6269879SRamaswamy.Tummala@Sun.COM 	    "enable", KSTAT_DATA_UINT32);
6279879SRamaswamy.Tummala@Sun.COM 	kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_XMIT_DATA_IDX],
6289879SRamaswamy.Tummala@Sun.COM 	    "xmit_data", KSTAT_DATA_UINT64);
6299879SRamaswamy.Tummala@Sun.COM 	kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_RECV_DATA_IDX],
6309879SRamaswamy.Tummala@Sun.COM 	    "recv_data", KSTAT_DATA_UINT64);
6319879SRamaswamy.Tummala@Sun.COM 	kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_XMIT_PKTS_IDX],
6329879SRamaswamy.Tummala@Sun.COM 	    "xmit_pkts", KSTAT_DATA_UINT64);
6339879SRamaswamy.Tummala@Sun.COM 	kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_RECV_PKTS_IDX],
6349879SRamaswamy.Tummala@Sun.COM 	    "recv_pkts", KSTAT_DATA_UINT64);
6359879SRamaswamy.Tummala@Sun.COM 
6369879SRamaswamy.Tummala@Sun.COM 	ksi->hki_perfcntr64[port_num - 1].hki64_ksp = cntr_ksp;
6379879SRamaswamy.Tummala@Sun.COM 	ksi->hki_perfcntr64[port_num - 1].hki64_port_num = port_num;
6389879SRamaswamy.Tummala@Sun.COM 	ksi->hki_perfcntr64[port_num - 1].hki64_state = state;
6399879SRamaswamy.Tummala@Sun.COM 
6409879SRamaswamy.Tummala@Sun.COM 	cntr_ksp->ks_private = &ksi->hki_perfcntr64[port_num - 1];
6419879SRamaswamy.Tummala@Sun.COM 	cntr_ksp->ks_update  = hermon_kstat_perfcntr64_update;
6429879SRamaswamy.Tummala@Sun.COM 
6439879SRamaswamy.Tummala@Sun.COM 	/* Install the kstat */
6449879SRamaswamy.Tummala@Sun.COM 	kstat_install(cntr_ksp);
6459879SRamaswamy.Tummala@Sun.COM }
6469879SRamaswamy.Tummala@Sun.COM 
6479879SRamaswamy.Tummala@Sun.COM /*
6489879SRamaswamy.Tummala@Sun.COM  * hermon_kstat_perfcntr64_read()
6499879SRamaswamy.Tummala@Sun.COM  *
6509879SRamaswamy.Tummala@Sun.COM  * Read the values of 32 bit hardware counters.
6519879SRamaswamy.Tummala@Sun.COM  *
6529879SRamaswamy.Tummala@Sun.COM  * If reset is true, reset the 32 bit hardware counters. Add the values of the
6539879SRamaswamy.Tummala@Sun.COM  * 32 bit hardware counters to the 64 bit software counters.
6549879SRamaswamy.Tummala@Sun.COM  *
6559879SRamaswamy.Tummala@Sun.COM  * If reset is false, just save the values read from the 32 bit hardware
6569879SRamaswamy.Tummala@Sun.COM  * counters in hki64_last_read[].
6579879SRamaswamy.Tummala@Sun.COM  *
6589879SRamaswamy.Tummala@Sun.COM  * See the general comment on the 64 bit performance counters
6599879SRamaswamy.Tummala@Sun.COM  * regarding the use of last read 32 bit hardware counter values.
6609879SRamaswamy.Tummala@Sun.COM  */
6619879SRamaswamy.Tummala@Sun.COM static int
hermon_kstat_perfcntr64_read(hermon_state_t * state,uint_t port,int reset)6629879SRamaswamy.Tummala@Sun.COM hermon_kstat_perfcntr64_read(hermon_state_t *state, uint_t port, int reset)
6639879SRamaswamy.Tummala@Sun.COM {
6649879SRamaswamy.Tummala@Sun.COM 	hermon_ks_info_t	*ksi = state->hs_ks_info;
6659879SRamaswamy.Tummala@Sun.COM 	hermon_perfcntr64_ks_info_t *ksi64 = &ksi->hki_perfcntr64[port - 1];
6669879SRamaswamy.Tummala@Sun.COM 	int			status, i;
6679879SRamaswamy.Tummala@Sun.COM 	uint32_t		tmp;
6689879SRamaswamy.Tummala@Sun.COM 	hermon_hw_sm_perfcntr_t	sm_perfcntr;
6699879SRamaswamy.Tummala@Sun.COM 
6709879SRamaswamy.Tummala@Sun.COM 	ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock));
6719879SRamaswamy.Tummala@Sun.COM 	ASSERT(port != 0);
6729879SRamaswamy.Tummala@Sun.COM 
6739879SRamaswamy.Tummala@Sun.COM 	/* read the 32 bit hardware counters */
6749879SRamaswamy.Tummala@Sun.COM 	status = hermon_getperfcntr_cmd_post(state, port,
6759879SRamaswamy.Tummala@Sun.COM 	    HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
6769879SRamaswamy.Tummala@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
6779879SRamaswamy.Tummala@Sun.COM 		return (status);
6789879SRamaswamy.Tummala@Sun.COM 	}
6799879SRamaswamy.Tummala@Sun.COM 
6809879SRamaswamy.Tummala@Sun.COM 	if (reset) {
6819879SRamaswamy.Tummala@Sun.COM 		/* reset the hardware counters */
6829879SRamaswamy.Tummala@Sun.COM 		status = hermon_getperfcntr_cmd_post(state, port,
6839879SRamaswamy.Tummala@Sun.COM 		    HERMON_CMD_NOSLEEP_SPIN, NULL, 1);
6849879SRamaswamy.Tummala@Sun.COM 		if (status != HERMON_CMD_SUCCESS) {
6859879SRamaswamy.Tummala@Sun.COM 			return (status);
6869879SRamaswamy.Tummala@Sun.COM 		}
6879879SRamaswamy.Tummala@Sun.COM 
6889879SRamaswamy.Tummala@Sun.COM 		/*
6899879SRamaswamy.Tummala@Sun.COM 		 * Update 64 bit software counters
6909879SRamaswamy.Tummala@Sun.COM 		 */
6919879SRamaswamy.Tummala@Sun.COM 		tmp = MAX(sm_perfcntr.portxmdata,
6929879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX]);
6939879SRamaswamy.Tummala@Sun.COM 		ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_DATA_IDX] += tmp;
6949879SRamaswamy.Tummala@Sun.COM 
6959879SRamaswamy.Tummala@Sun.COM 		tmp = MAX(sm_perfcntr.portrcdata,
6969879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX]);
6979879SRamaswamy.Tummala@Sun.COM 		ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_DATA_IDX] += tmp;
6989879SRamaswamy.Tummala@Sun.COM 
6999879SRamaswamy.Tummala@Sun.COM 		tmp = MAX(sm_perfcntr.portxmpkts,
7009879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX]);
7019879SRamaswamy.Tummala@Sun.COM 		ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_PKTS_IDX] += tmp;
7029879SRamaswamy.Tummala@Sun.COM 
7039879SRamaswamy.Tummala@Sun.COM 		tmp = MAX(sm_perfcntr.portrcpkts,
7049879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX]);
7059879SRamaswamy.Tummala@Sun.COM 		ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_PKTS_IDX] += tmp;
7069879SRamaswamy.Tummala@Sun.COM 
7079879SRamaswamy.Tummala@Sun.COM 		for (i = 0; i < HERMON_PERFCNTR64_NUM_COUNTERS; i++)
7089879SRamaswamy.Tummala@Sun.COM 			ksi64->hki64_last_read[i] = 0;
7099879SRamaswamy.Tummala@Sun.COM 
7109879SRamaswamy.Tummala@Sun.COM 	} else {
7119879SRamaswamy.Tummala@Sun.COM 		/*
7129879SRamaswamy.Tummala@Sun.COM 		 * Update ksi64->hki64_last_read[]
7139879SRamaswamy.Tummala@Sun.COM 		 */
7149879SRamaswamy.Tummala@Sun.COM 		SET_TO_MAX(
7159879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX],
7169879SRamaswamy.Tummala@Sun.COM 		    sm_perfcntr.portxmdata);
7179879SRamaswamy.Tummala@Sun.COM 
7189879SRamaswamy.Tummala@Sun.COM 		SET_TO_MAX(
7199879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX],
7209879SRamaswamy.Tummala@Sun.COM 		    sm_perfcntr.portrcdata);
7219879SRamaswamy.Tummala@Sun.COM 
7229879SRamaswamy.Tummala@Sun.COM 		SET_TO_MAX(
7239879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX],
7249879SRamaswamy.Tummala@Sun.COM 		    sm_perfcntr.portxmpkts);
7259879SRamaswamy.Tummala@Sun.COM 
7269879SRamaswamy.Tummala@Sun.COM 		SET_TO_MAX(
7279879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX],
7289879SRamaswamy.Tummala@Sun.COM 		    sm_perfcntr.portrcpkts);
7299879SRamaswamy.Tummala@Sun.COM 	}
7309879SRamaswamy.Tummala@Sun.COM 
7319879SRamaswamy.Tummala@Sun.COM 	return (HERMON_CMD_SUCCESS);
7329879SRamaswamy.Tummala@Sun.COM }
7339879SRamaswamy.Tummala@Sun.COM 
7349879SRamaswamy.Tummala@Sun.COM /*
7359879SRamaswamy.Tummala@Sun.COM  * hermon_kstat_perfcntr64_update_thread()
7369879SRamaswamy.Tummala@Sun.COM  *    Context: Entry point for a kernel thread
7379879SRamaswamy.Tummala@Sun.COM  *
7389879SRamaswamy.Tummala@Sun.COM  * Maintain 64 bit performance counters in software using the 32 bit
7399879SRamaswamy.Tummala@Sun.COM  * hardware counters.
7409879SRamaswamy.Tummala@Sun.COM  */
7419879SRamaswamy.Tummala@Sun.COM static void
hermon_kstat_perfcntr64_update_thread(void * arg)7429879SRamaswamy.Tummala@Sun.COM hermon_kstat_perfcntr64_update_thread(void *arg)
7439879SRamaswamy.Tummala@Sun.COM {
7449879SRamaswamy.Tummala@Sun.COM 	hermon_state_t		*state = (hermon_state_t *)arg;
7459879SRamaswamy.Tummala@Sun.COM 	hermon_ks_info_t	*ksi = state->hs_ks_info;
7469879SRamaswamy.Tummala@Sun.COM 	uint_t			i;
74711066Srafael.vanoni@sun.com 	clock_t			delta = drv_usectohz(1000000);
7489879SRamaswamy.Tummala@Sun.COM 
7499879SRamaswamy.Tummala@Sun.COM 	mutex_enter(&ksi->hki_perfcntr64_lock);
7509879SRamaswamy.Tummala@Sun.COM 	/*
7519879SRamaswamy.Tummala@Sun.COM 	 * Every one second update the values 64 bit software counters
7529879SRamaswamy.Tummala@Sun.COM 	 * for all ports. Exit if HERMON_PERFCNTR64_THREAD_EXIT flag is set.
7539879SRamaswamy.Tummala@Sun.COM 	 */
7549879SRamaswamy.Tummala@Sun.COM 	while (!(ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_EXIT)) {
7559879SRamaswamy.Tummala@Sun.COM 		for (i = 0; i < state->hs_cfg_profile->cp_num_ports; i++) {
7569879SRamaswamy.Tummala@Sun.COM 			if (ksi->hki_perfcntr64[i].hki64_enabled) {
7579879SRamaswamy.Tummala@Sun.COM 				(void) hermon_kstat_perfcntr64_read(state,
7589879SRamaswamy.Tummala@Sun.COM 				    i + 1, 1);
7599879SRamaswamy.Tummala@Sun.COM 			}
7609879SRamaswamy.Tummala@Sun.COM 		}
7619879SRamaswamy.Tummala@Sun.COM 		/* sleep for a second */
76211066Srafael.vanoni@sun.com 		(void) cv_reltimedwait(&ksi->hki_perfcntr64_cv,
76311066Srafael.vanoni@sun.com 		    &ksi->hki_perfcntr64_lock, delta, TR_CLOCK_TICK);
7649879SRamaswamy.Tummala@Sun.COM 	}
7659879SRamaswamy.Tummala@Sun.COM 	ksi->hki_perfcntr64_flags = 0;
7669879SRamaswamy.Tummala@Sun.COM 	mutex_exit(&ksi->hki_perfcntr64_lock);
7679879SRamaswamy.Tummala@Sun.COM }
7689879SRamaswamy.Tummala@Sun.COM 
7699879SRamaswamy.Tummala@Sun.COM /*
7709879SRamaswamy.Tummala@Sun.COM  * hermon_kstat_perfcntr64_thread_create()
7719879SRamaswamy.Tummala@Sun.COM  *    Context: Called from the kstat context
7729879SRamaswamy.Tummala@Sun.COM  *
7739879SRamaswamy.Tummala@Sun.COM  * Create a thread that maintains 64 bit performance counters in software.
7749879SRamaswamy.Tummala@Sun.COM  */
7759879SRamaswamy.Tummala@Sun.COM static void
hermon_kstat_perfcntr64_thread_create(hermon_state_t * state)7769879SRamaswamy.Tummala@Sun.COM hermon_kstat_perfcntr64_thread_create(hermon_state_t *state)
7779879SRamaswamy.Tummala@Sun.COM {
7789879SRamaswamy.Tummala@Sun.COM 	hermon_ks_info_t	*ksi = state->hs_ks_info;
7799879SRamaswamy.Tummala@Sun.COM 	kthread_t		*thr;
7809879SRamaswamy.Tummala@Sun.COM 
7819879SRamaswamy.Tummala@Sun.COM 	ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock));
7829879SRamaswamy.Tummala@Sun.COM 
7839879SRamaswamy.Tummala@Sun.COM 	/*
7849879SRamaswamy.Tummala@Sun.COM 	 * One thread per hermon instance. Don't create a thread if already
7859879SRamaswamy.Tummala@Sun.COM 	 * created.
7869879SRamaswamy.Tummala@Sun.COM 	 */
7879879SRamaswamy.Tummala@Sun.COM 	if (!(ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_CREATED)) {
7889879SRamaswamy.Tummala@Sun.COM 		thr = thread_create(NULL, 0,
7899879SRamaswamy.Tummala@Sun.COM 		    hermon_kstat_perfcntr64_update_thread,
7909879SRamaswamy.Tummala@Sun.COM 		    state, 0, &p0, TS_RUN, minclsyspri);
7919879SRamaswamy.Tummala@Sun.COM 		ksi->hki_perfcntr64_thread_id = thr->t_did;
7929879SRamaswamy.Tummala@Sun.COM 		ksi->hki_perfcntr64_flags |= HERMON_PERFCNTR64_THREAD_CREATED;
7939879SRamaswamy.Tummala@Sun.COM 	}
7949879SRamaswamy.Tummala@Sun.COM }
7959879SRamaswamy.Tummala@Sun.COM 
7969879SRamaswamy.Tummala@Sun.COM /*
7979879SRamaswamy.Tummala@Sun.COM  * hermon_kstat_perfcntr64_thread_exit()
7989879SRamaswamy.Tummala@Sun.COM  *    Context: Called from attach, detach or kstat context
7999879SRamaswamy.Tummala@Sun.COM  */
8009879SRamaswamy.Tummala@Sun.COM static void
hermon_kstat_perfcntr64_thread_exit(hermon_ks_info_t * ksi)8019879SRamaswamy.Tummala@Sun.COM hermon_kstat_perfcntr64_thread_exit(hermon_ks_info_t *ksi)
8029879SRamaswamy.Tummala@Sun.COM {
8039879SRamaswamy.Tummala@Sun.COM 	kt_did_t	tid;
8049879SRamaswamy.Tummala@Sun.COM 
8059879SRamaswamy.Tummala@Sun.COM 	ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock));
8069879SRamaswamy.Tummala@Sun.COM 
8079879SRamaswamy.Tummala@Sun.COM 	if (ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_CREATED) {
8089879SRamaswamy.Tummala@Sun.COM 		/*
8099879SRamaswamy.Tummala@Sun.COM 		 * Signal the thread to exit and wait until the thread exits.
8109879SRamaswamy.Tummala@Sun.COM 		 */
8119879SRamaswamy.Tummala@Sun.COM 		ksi->hki_perfcntr64_flags |= HERMON_PERFCNTR64_THREAD_EXIT;
8129879SRamaswamy.Tummala@Sun.COM 		tid = ksi->hki_perfcntr64_thread_id;
8139879SRamaswamy.Tummala@Sun.COM 		cv_signal(&ksi->hki_perfcntr64_cv);
8149879SRamaswamy.Tummala@Sun.COM 
8159879SRamaswamy.Tummala@Sun.COM 		mutex_exit(&ksi->hki_perfcntr64_lock);
8169879SRamaswamy.Tummala@Sun.COM 		thread_join(tid);
8179879SRamaswamy.Tummala@Sun.COM 		mutex_enter(&ksi->hki_perfcntr64_lock);
8189879SRamaswamy.Tummala@Sun.COM 	}
8199879SRamaswamy.Tummala@Sun.COM }
8209879SRamaswamy.Tummala@Sun.COM 
8219879SRamaswamy.Tummala@Sun.COM /*
822*11190SRamaswamy.Tummala@Sun.COM  * hermon_kstat_perfcntr64_update_ext()
823*11190SRamaswamy.Tummala@Sun.COM  *    Context: Called from the kstat context
824*11190SRamaswamy.Tummala@Sun.COM  *
825*11190SRamaswamy.Tummala@Sun.COM  * Update perf_counters kstats with the values of the extended port counters
826*11190SRamaswamy.Tummala@Sun.COM  * from the hardware.
827*11190SRamaswamy.Tummala@Sun.COM  */
828*11190SRamaswamy.Tummala@Sun.COM static int
hermon_kstat_perfcntr64_update_ext(hermon_perfcntr64_ks_info_t * ksi64,int rw,struct kstat_named * data)829*11190SRamaswamy.Tummala@Sun.COM hermon_kstat_perfcntr64_update_ext(hermon_perfcntr64_ks_info_t *ksi64, int rw,
830*11190SRamaswamy.Tummala@Sun.COM     struct kstat_named *data)
831*11190SRamaswamy.Tummala@Sun.COM {
832*11190SRamaswamy.Tummala@Sun.COM 	hermon_hw_sm_extperfcntr_t	sm_extperfcntr;
833*11190SRamaswamy.Tummala@Sun.COM 
834*11190SRamaswamy.Tummala@Sun.COM 	/*
835*11190SRamaswamy.Tummala@Sun.COM 	 * The "enable" component of the kstat is the only writable kstat.
836*11190SRamaswamy.Tummala@Sun.COM 	 * It is a no-op when the hardware supports extended port counters.
837*11190SRamaswamy.Tummala@Sun.COM 	 */
838*11190SRamaswamy.Tummala@Sun.COM 	if (rw == KSTAT_WRITE)
839*11190SRamaswamy.Tummala@Sun.COM 		return (0);
840*11190SRamaswamy.Tummala@Sun.COM 
841*11190SRamaswamy.Tummala@Sun.COM 	/*
842*11190SRamaswamy.Tummala@Sun.COM 	 * Read the counters and update kstats.
843*11190SRamaswamy.Tummala@Sun.COM 	 */
844*11190SRamaswamy.Tummala@Sun.COM 	if (hermon_getextperfcntr_cmd_post(ksi64->hki64_state,
845*11190SRamaswamy.Tummala@Sun.COM 	    ksi64->hki64_port_num, HERMON_CMD_NOSLEEP_SPIN, &sm_extperfcntr) !=
846*11190SRamaswamy.Tummala@Sun.COM 	    HERMON_CMD_SUCCESS) {
847*11190SRamaswamy.Tummala@Sun.COM 		return (EIO);
848*11190SRamaswamy.Tummala@Sun.COM 	}
849*11190SRamaswamy.Tummala@Sun.COM 
850*11190SRamaswamy.Tummala@Sun.COM 	data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 1;
851*11190SRamaswamy.Tummala@Sun.COM 
852*11190SRamaswamy.Tummala@Sun.COM 	data[HERMON_PERFCNTR64_XMIT_DATA_IDX].value.ui64 =
853*11190SRamaswamy.Tummala@Sun.COM 	    sm_extperfcntr.portxmdata;
854*11190SRamaswamy.Tummala@Sun.COM 
855*11190SRamaswamy.Tummala@Sun.COM 	data[HERMON_PERFCNTR64_RECV_DATA_IDX].value.ui64 =
856*11190SRamaswamy.Tummala@Sun.COM 	    sm_extperfcntr.portrcdata;
857*11190SRamaswamy.Tummala@Sun.COM 
858*11190SRamaswamy.Tummala@Sun.COM 	data[HERMON_PERFCNTR64_XMIT_PKTS_IDX].value.ui64 =
859*11190SRamaswamy.Tummala@Sun.COM 	    sm_extperfcntr.portxmpkts;
860*11190SRamaswamy.Tummala@Sun.COM 
861*11190SRamaswamy.Tummala@Sun.COM 	data[HERMON_PERFCNTR64_RECV_PKTS_IDX].value.ui64 =
862*11190SRamaswamy.Tummala@Sun.COM 	    sm_extperfcntr.portrcpkts;
863*11190SRamaswamy.Tummala@Sun.COM 
864*11190SRamaswamy.Tummala@Sun.COM 	return (0);
865*11190SRamaswamy.Tummala@Sun.COM }
866*11190SRamaswamy.Tummala@Sun.COM 
867*11190SRamaswamy.Tummala@Sun.COM /*
8689879SRamaswamy.Tummala@Sun.COM  * hermon_kstat_perfcntr64_update()
8699879SRamaswamy.Tummala@Sun.COM  *    Context: Called from the kstat context
8709879SRamaswamy.Tummala@Sun.COM  *
8719879SRamaswamy.Tummala@Sun.COM  * See the general comment on 64 bit kstats for performance counters:
8729879SRamaswamy.Tummala@Sun.COM  */
8739879SRamaswamy.Tummala@Sun.COM static int
hermon_kstat_perfcntr64_update(kstat_t * ksp,int rw)8749879SRamaswamy.Tummala@Sun.COM hermon_kstat_perfcntr64_update(kstat_t *ksp, int rw)
8759879SRamaswamy.Tummala@Sun.COM {
8769879SRamaswamy.Tummala@Sun.COM 	hermon_state_t			*state;
8779879SRamaswamy.Tummala@Sun.COM 	struct kstat_named		*data;
8789879SRamaswamy.Tummala@Sun.COM 	hermon_ks_info_t		*ksi;
8799879SRamaswamy.Tummala@Sun.COM 	hermon_perfcntr64_ks_info_t	*ksi64;
8809879SRamaswamy.Tummala@Sun.COM 	int				i, thr_exit;
881*11190SRamaswamy.Tummala@Sun.COM 	int				rv;
8829879SRamaswamy.Tummala@Sun.COM 
8839879SRamaswamy.Tummala@Sun.COM 	ksi64	= ksp->ks_private;
8849879SRamaswamy.Tummala@Sun.COM 	state	= ksi64->hki64_state;
8859879SRamaswamy.Tummala@Sun.COM 	ksi	= state->hs_ks_info;
8869879SRamaswamy.Tummala@Sun.COM 	data	= (struct kstat_named *)(ksp->ks_data);
8879879SRamaswamy.Tummala@Sun.COM 
8889879SRamaswamy.Tummala@Sun.COM 	mutex_enter(&ksi->hki_perfcntr64_lock);
8899879SRamaswamy.Tummala@Sun.COM 
890*11190SRamaswamy.Tummala@Sun.COM 	if (ksi64->hki64_ext_port_counters_supported) {
891*11190SRamaswamy.Tummala@Sun.COM 		rv = hermon_kstat_perfcntr64_update_ext(ksi64, rw, data);
892*11190SRamaswamy.Tummala@Sun.COM 		mutex_exit(&ksi->hki_perfcntr64_lock);
893*11190SRamaswamy.Tummala@Sun.COM 		return (rv);
894*11190SRamaswamy.Tummala@Sun.COM 	}
895*11190SRamaswamy.Tummala@Sun.COM 
8969879SRamaswamy.Tummala@Sun.COM 	/*
8979879SRamaswamy.Tummala@Sun.COM 	 * 64 bit performance counters maintained by the software is not
8989879SRamaswamy.Tummala@Sun.COM 	 * enabled by default. Enable them upon a writing a non-zero value
8999879SRamaswamy.Tummala@Sun.COM 	 * to "enable" kstat. Disable them upon a writing zero to the
9009879SRamaswamy.Tummala@Sun.COM 	 * "enable" kstat.
9019879SRamaswamy.Tummala@Sun.COM 	 */
9029879SRamaswamy.Tummala@Sun.COM 	if (rw == KSTAT_WRITE) {
9039879SRamaswamy.Tummala@Sun.COM 		if (data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32) {
9049879SRamaswamy.Tummala@Sun.COM 			if (ksi64->hki64_enabled == 0) {
9059899SRamaswamy.Tummala@Sun.COM 				/*
9069899SRamaswamy.Tummala@Sun.COM 				 * Reset the hardware counters to ensure that
9079899SRamaswamy.Tummala@Sun.COM 				 * the hardware counter doesn't max out
9089899SRamaswamy.Tummala@Sun.COM 				 * (and hence stop counting) before we get
9099899SRamaswamy.Tummala@Sun.COM 				 * a chance to reset the counter in
9109899SRamaswamy.Tummala@Sun.COM 				 * hermon_kstat_perfcntr64_update_thread.
9119899SRamaswamy.Tummala@Sun.COM 				 */
9129899SRamaswamy.Tummala@Sun.COM 				if (hermon_getperfcntr_cmd_post(state,
9139899SRamaswamy.Tummala@Sun.COM 				    ksi64->hki64_port_num,
9149899SRamaswamy.Tummala@Sun.COM 				    HERMON_CMD_NOSLEEP_SPIN, NULL, 1) !=
9159899SRamaswamy.Tummala@Sun.COM 				    HERMON_CMD_SUCCESS) {
9169899SRamaswamy.Tummala@Sun.COM 					mutex_exit(&ksi->hki_perfcntr64_lock);
9179899SRamaswamy.Tummala@Sun.COM 					return (EIO);
9189899SRamaswamy.Tummala@Sun.COM 				}
9199899SRamaswamy.Tummala@Sun.COM 
9209879SRamaswamy.Tummala@Sun.COM 				/* Enable 64 bit software counters */
9219879SRamaswamy.Tummala@Sun.COM 				ksi64->hki64_enabled = 1;
9229879SRamaswamy.Tummala@Sun.COM 				for (i = 0;
9239879SRamaswamy.Tummala@Sun.COM 				    i < HERMON_PERFCNTR64_NUM_COUNTERS; i++) {
9249879SRamaswamy.Tummala@Sun.COM 					ksi64->hki64_counters[i] = 0;
9259879SRamaswamy.Tummala@Sun.COM 					ksi64->hki64_last_read[i] = 0;
9269879SRamaswamy.Tummala@Sun.COM 				}
9279879SRamaswamy.Tummala@Sun.COM 				hermon_kstat_perfcntr64_thread_create(state);
9289879SRamaswamy.Tummala@Sun.COM 			}
9299879SRamaswamy.Tummala@Sun.COM 
9309879SRamaswamy.Tummala@Sun.COM 		} else if (ksi64->hki64_enabled) {
9319879SRamaswamy.Tummala@Sun.COM 			/* Disable 64 bit software counters */
9329879SRamaswamy.Tummala@Sun.COM 			ksi64->hki64_enabled = 0;
9339879SRamaswamy.Tummala@Sun.COM 			thr_exit = 1;
9349879SRamaswamy.Tummala@Sun.COM 			for (i = 0; i < state->hs_cfg_profile->cp_num_ports;
9359879SRamaswamy.Tummala@Sun.COM 			    i++) {
9369879SRamaswamy.Tummala@Sun.COM 				if (ksi->hki_perfcntr64[i].hki64_enabled) {
9379879SRamaswamy.Tummala@Sun.COM 					thr_exit = 0;
9389879SRamaswamy.Tummala@Sun.COM 					break;
9399879SRamaswamy.Tummala@Sun.COM 				}
9409879SRamaswamy.Tummala@Sun.COM 			}
9419879SRamaswamy.Tummala@Sun.COM 			if (thr_exit)
9429879SRamaswamy.Tummala@Sun.COM 				hermon_kstat_perfcntr64_thread_exit(ksi);
9439879SRamaswamy.Tummala@Sun.COM 		}
9449879SRamaswamy.Tummala@Sun.COM 	} else if (ksi64->hki64_enabled) {
9459879SRamaswamy.Tummala@Sun.COM 		/*
9469879SRamaswamy.Tummala@Sun.COM 		 * Read the counters and update kstats.
9479879SRamaswamy.Tummala@Sun.COM 		 */
9489879SRamaswamy.Tummala@Sun.COM 		if (hermon_kstat_perfcntr64_read(state, ksi64->hki64_port_num,
9499879SRamaswamy.Tummala@Sun.COM 		    0) != HERMON_CMD_SUCCESS) {
9509879SRamaswamy.Tummala@Sun.COM 			mutex_exit(&ksi->hki_perfcntr64_lock);
9519879SRamaswamy.Tummala@Sun.COM 			return (EIO);
9529879SRamaswamy.Tummala@Sun.COM 		}
9539879SRamaswamy.Tummala@Sun.COM 
9549899SRamaswamy.Tummala@Sun.COM 		data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 1;
9559899SRamaswamy.Tummala@Sun.COM 
9569879SRamaswamy.Tummala@Sun.COM 		data[HERMON_PERFCNTR64_XMIT_DATA_IDX].value.ui64 =
9579879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_DATA_IDX] +
9589879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX];
9599879SRamaswamy.Tummala@Sun.COM 
9609879SRamaswamy.Tummala@Sun.COM 		data[HERMON_PERFCNTR64_RECV_DATA_IDX].value.ui64 =
9619879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_DATA_IDX] +
9629879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX];
9639879SRamaswamy.Tummala@Sun.COM 
9649879SRamaswamy.Tummala@Sun.COM 		data[HERMON_PERFCNTR64_XMIT_PKTS_IDX].value.ui64 =
9659879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_PKTS_IDX] +
9669879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX];
9679879SRamaswamy.Tummala@Sun.COM 
9689879SRamaswamy.Tummala@Sun.COM 		data[HERMON_PERFCNTR64_RECV_PKTS_IDX].value.ui64 =
9699879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_PKTS_IDX] +
9709879SRamaswamy.Tummala@Sun.COM 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX];
9719879SRamaswamy.Tummala@Sun.COM 
9729879SRamaswamy.Tummala@Sun.COM 	} else {
9739879SRamaswamy.Tummala@Sun.COM 		/* return 0 in kstats if not enabled */
9749879SRamaswamy.Tummala@Sun.COM 		data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 0;
9759879SRamaswamy.Tummala@Sun.COM 		for (i = 1; i < HERMON_PERFCNTR64_NUM_COUNTERS; i++)
9769879SRamaswamy.Tummala@Sun.COM 			data[i].value.ui64 = 0;
9779879SRamaswamy.Tummala@Sun.COM 	}
9789879SRamaswamy.Tummala@Sun.COM 
9799879SRamaswamy.Tummala@Sun.COM 	mutex_exit(&ksi->hki_perfcntr64_lock);
9809879SRamaswamy.Tummala@Sun.COM 	return (0);
9819879SRamaswamy.Tummala@Sun.COM }
982