19e39c5baSBill Taylor /*
29e39c5baSBill Taylor  * CDDL HEADER START
39e39c5baSBill Taylor  *
49e39c5baSBill Taylor  * The contents of this file are subject to the terms of the
59e39c5baSBill Taylor  * Common Development and Distribution License (the "License").
69e39c5baSBill Taylor  * You may not use this file except in compliance with the License.
79e39c5baSBill Taylor  *
89e39c5baSBill Taylor  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99e39c5baSBill Taylor  * or http://www.opensolaris.org/os/licensing.
109e39c5baSBill Taylor  * See the License for the specific language governing permissions
119e39c5baSBill Taylor  * and limitations under the License.
129e39c5baSBill Taylor  *
139e39c5baSBill Taylor  * When distributing Covered Code, include this CDDL HEADER in each
149e39c5baSBill Taylor  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159e39c5baSBill Taylor  * If applicable, add the following below this CDDL HEADER, with the
169e39c5baSBill Taylor  * fields enclosed by brackets "[]" replaced with your own identifying
179e39c5baSBill Taylor  * information: Portions Copyright [yyyy] [name of copyright owner]
189e39c5baSBill Taylor  *
199e39c5baSBill Taylor  * CDDL HEADER END
209e39c5baSBill Taylor  */
219e39c5baSBill Taylor 
229e39c5baSBill Taylor /*
239e39c5baSBill Taylor  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
249e39c5baSBill Taylor  * Use is subject to license terms.
259e39c5baSBill Taylor  */
269e39c5baSBill Taylor 
279e39c5baSBill Taylor /*
289e39c5baSBill Taylor  * hermon_stats.c
299e39c5baSBill Taylor  *    Hermon IB Performance Statistics routines
309e39c5baSBill Taylor  *
319e39c5baSBill Taylor  *    Implements all the routines necessary for setting up, querying, and
329e39c5baSBill Taylor  *    (later) tearing down all the kstats necessary for implementing to
33*bbf21555SRichard Lowe  *    the interfaces necessary to provide busstat(8) access.
349e39c5baSBill Taylor  */
359e39c5baSBill Taylor 
369e39c5baSBill Taylor #include <sys/types.h>
379e39c5baSBill Taylor #include <sys/conf.h>
389e39c5baSBill Taylor #include <sys/ddi.h>
399e39c5baSBill Taylor #include <sys/sunddi.h>
409e39c5baSBill Taylor #include <sys/modctl.h>
419e39c5baSBill Taylor 
429e39c5baSBill Taylor #include <sys/ib/adapters/hermon/hermon.h>
439e39c5baSBill Taylor 
449e39c5baSBill Taylor static kstat_t *hermon_kstat_picN_create(hermon_state_t *state, int num_pic,
459e39c5baSBill Taylor     int num_evt, hermon_ks_mask_t *ev_array);
469e39c5baSBill Taylor static kstat_t *hermon_kstat_cntr_create(hermon_state_t *state, int num_pic,
479e39c5baSBill Taylor     int (*update)(kstat_t *, int));
489e39c5baSBill Taylor static int hermon_kstat_cntr_update(kstat_t *ksp, int rw);
499e39c5baSBill Taylor 
50d1a5c838SRamaswamy Tummala void hermon_kstat_perfcntr64_create(hermon_state_t *state, uint_t port_num);
51d1a5c838SRamaswamy Tummala static int hermon_kstat_perfcntr64_read(hermon_state_t *state, uint_t port,
52d1a5c838SRamaswamy Tummala     int reset);
53d1a5c838SRamaswamy Tummala static void hermon_kstat_perfcntr64_thread_exit(hermon_ks_info_t *ksi);
54d1a5c838SRamaswamy Tummala static int hermon_kstat_perfcntr64_update(kstat_t *ksp, int rw);
55d1a5c838SRamaswamy Tummala 
569e39c5baSBill Taylor /*
579e39c5baSBill Taylor  * Hermon IB Performance Events structure
589e39c5baSBill Taylor  *    This structure is read-only and is used to setup the individual kstats
599e39c5baSBill Taylor  *    and to initialize the tki_ib_perfcnt[] array for each Hermon instance.
609e39c5baSBill Taylor  */
619e39c5baSBill Taylor hermon_ks_mask_t hermon_ib_perfcnt_list[HERMON_CNTR_NUMENTRIES] = {
629e39c5baSBill Taylor 	{"port_xmit_data", 0, 0},
639e39c5baSBill Taylor 	{"port_recv_data", 0, 0},
649e39c5baSBill Taylor 	{"port_xmit_pkts", 0, 0},
659e39c5baSBill Taylor 	{"port_recv_pkts", 0, 0},
669e39c5baSBill Taylor 	{"port_recv_err", 0, 0},
679e39c5baSBill Taylor 	{"port_xmit_discards", 0, 0},
689e39c5baSBill Taylor 	{"vl15_dropped", 0, 0},
699e39c5baSBill Taylor 	{"port_xmit_wait", 0, 0},
709e39c5baSBill Taylor 	{"port_recv_remote_phys_err", 0, 0},
719e39c5baSBill Taylor 	{"port_xmit_constraint_err", 0, 0},
729e39c5baSBill Taylor 	{"port_recv_constraint_err", 0, 0},
739e39c5baSBill Taylor 	{"symbol_err_counter", 0, 0},
749e39c5baSBill Taylor 	{"link_err_recovery_cnt", 0, 0},
759e39c5baSBill Taylor 	{"link_downed_cnt", 0, 0},
769e39c5baSBill Taylor 	{"excessive_buffer_overruns", 0, 0},
779e39c5baSBill Taylor 	{"local_link_integrity_err", 0, 0},
789e39c5baSBill Taylor 	{"clear_pic", 0, 0}
799e39c5baSBill Taylor };
809e39c5baSBill Taylor 
81d1a5c838SRamaswamy Tummala /*
82d1a5c838SRamaswamy Tummala  * Return the maximum of (x) and (y)
83d1a5c838SRamaswamy Tummala  */
84d1a5c838SRamaswamy Tummala #define	MAX(x, y)	(((x) > (y)) ? (x) : (y))
85d1a5c838SRamaswamy Tummala 
86d1a5c838SRamaswamy Tummala /*
87d1a5c838SRamaswamy Tummala  * Set (x) to the maximum of (x) and (y)
88d1a5c838SRamaswamy Tummala  */
89d1a5c838SRamaswamy Tummala #define	SET_TO_MAX(x, y)	\
90d1a5c838SRamaswamy Tummala {				\
91d1a5c838SRamaswamy Tummala 	if ((x) < (y))		\
92d1a5c838SRamaswamy Tummala 		(x) = (y);	\
93d1a5c838SRamaswamy Tummala }
949e39c5baSBill Taylor 
959e39c5baSBill Taylor /*
969e39c5baSBill Taylor  * hermon_kstat_init()
979e39c5baSBill Taylor  *    Context: Only called from attach() path context
989e39c5baSBill Taylor  */
999e39c5baSBill Taylor int
hermon_kstat_init(hermon_state_t * state)1009e39c5baSBill Taylor hermon_kstat_init(hermon_state_t *state)
1019e39c5baSBill Taylor {
1029e39c5baSBill Taylor 	hermon_ks_info_t		*ksi;
1039e39c5baSBill Taylor 	uint_t			numports;
1049e39c5baSBill Taylor 	int			i;
1059e39c5baSBill Taylor 
1069e39c5baSBill Taylor 	/* Allocate a kstat info structure */
1079e39c5baSBill Taylor 	ksi = (hermon_ks_info_t *)kmem_zalloc(sizeof (hermon_ks_info_t),
1089e39c5baSBill Taylor 	    KM_SLEEP);
1099e39c5baSBill Taylor 	if (ksi == NULL) {
1109e39c5baSBill Taylor 		return (DDI_FAILURE);
1119e39c5baSBill Taylor 	}
1129e39c5baSBill Taylor 	state->hs_ks_info = ksi;
1139e39c5baSBill Taylor 
1149e39c5baSBill Taylor 	/*
115d1a5c838SRamaswamy Tummala 	 * Create as many "pic" and perfcntr64 kstats as we have IB ports.
116d1a5c838SRamaswamy Tummala 	 * Enable all of the events specified in the "hermon_ib_perfcnt_list"
117d1a5c838SRamaswamy Tummala 	 * structure.
1189e39c5baSBill Taylor 	 */
1199e39c5baSBill Taylor 	numports = state->hs_cfg_profile->cp_num_ports;
1209e39c5baSBill Taylor 	for (i = 0; i < numports; i++) {
1219e39c5baSBill Taylor 		ksi->hki_picN_ksp[i] = hermon_kstat_picN_create(state, i,
1229e39c5baSBill Taylor 		    HERMON_CNTR_NUMENTRIES, hermon_ib_perfcnt_list);
1239e39c5baSBill Taylor 		if (ksi->hki_picN_ksp[i] == NULL) {
1249e39c5baSBill Taylor 			goto kstat_init_fail;
1259e39c5baSBill Taylor 		}
126d1a5c838SRamaswamy Tummala 
127d1a5c838SRamaswamy Tummala 		hermon_kstat_perfcntr64_create(state, i + 1);
128d1a5c838SRamaswamy Tummala 		if (ksi->hki_perfcntr64[i].hki64_ksp == NULL) {
129d1a5c838SRamaswamy Tummala 			goto kstat_init_fail;
130d1a5c838SRamaswamy Tummala 		}
1319e39c5baSBill Taylor 	}
1329e39c5baSBill Taylor 
1339e39c5baSBill Taylor 	/* Create the "counters" kstat too */
1349e39c5baSBill Taylor 	ksi->hki_cntr_ksp = hermon_kstat_cntr_create(state, numports,
1359e39c5baSBill Taylor 	    hermon_kstat_cntr_update);
1369e39c5baSBill Taylor 	if (ksi->hki_cntr_ksp == NULL) {
1379e39c5baSBill Taylor 		goto kstat_init_fail;
1389e39c5baSBill Taylor 	}
1399e39c5baSBill Taylor 
1409e39c5baSBill Taylor 	/* Initialize the control register and initial counter values */
1419e39c5baSBill Taylor 	ksi->hki_pcr  = 0;
1429e39c5baSBill Taylor 	ksi->hki_pic0 = 0;
1439e39c5baSBill Taylor 	ksi->hki_pic1 = 0;
1449e39c5baSBill Taylor 
1459e39c5baSBill Taylor 	/*
1469e39c5baSBill Taylor 	 * Initialize the Hermon hki_ib_perfcnt[] array values using the
1479e39c5baSBill Taylor 	 * default values in hermon_ib_perfcnt_list[]
1489e39c5baSBill Taylor 	 */
1499e39c5baSBill Taylor 	for (i = 0; i < HERMON_CNTR_NUMENTRIES; i++) {
1509e39c5baSBill Taylor 		ksi->hki_ib_perfcnt[i] = hermon_ib_perfcnt_list[i];
1519e39c5baSBill Taylor 	}
1529e39c5baSBill Taylor 
153d1a5c838SRamaswamy Tummala 	mutex_init(&ksi->hki_perfcntr64_lock, NULL, MUTEX_DRIVER, NULL);
154d1a5c838SRamaswamy Tummala 	cv_init(&ksi->hki_perfcntr64_cv, NULL, CV_DRIVER, NULL);
155d1a5c838SRamaswamy Tummala 
1569e39c5baSBill Taylor 	return (DDI_SUCCESS);
1579e39c5baSBill Taylor 
1589e39c5baSBill Taylor 
1599e39c5baSBill Taylor kstat_init_fail:
1609e39c5baSBill Taylor 
1619e39c5baSBill Taylor 	/* Delete all the previously created kstats */
1629e39c5baSBill Taylor 	if (ksi->hki_cntr_ksp != NULL) {
1639e39c5baSBill Taylor 		kstat_delete(ksi->hki_cntr_ksp);
1649e39c5baSBill Taylor 	}
1659e39c5baSBill Taylor 	for (i = 0; i < numports; i++) {
1669e39c5baSBill Taylor 		if (ksi->hki_picN_ksp[i] != NULL) {
1679e39c5baSBill Taylor 			kstat_delete(ksi->hki_picN_ksp[i]);
1689e39c5baSBill Taylor 		}
169d1a5c838SRamaswamy Tummala 		if (ksi->hki_perfcntr64[i].hki64_ksp != NULL) {
170d1a5c838SRamaswamy Tummala 			kstat_delete(ksi->hki_perfcntr64[i].hki64_ksp);
171d1a5c838SRamaswamy Tummala 		}
1729e39c5baSBill Taylor 	}
1739e39c5baSBill Taylor 
1749e39c5baSBill Taylor 	/* Free the kstat info structure */
1759e39c5baSBill Taylor 	kmem_free(ksi, sizeof (hermon_ks_info_t));
1769e39c5baSBill Taylor 
1779e39c5baSBill Taylor 	return (DDI_FAILURE);
1789e39c5baSBill Taylor }
1799e39c5baSBill Taylor 
1809e39c5baSBill Taylor 
1819e39c5baSBill Taylor /*
1829e39c5baSBill Taylor  * hermon_kstat_init()
1839e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
1849e39c5baSBill Taylor  */
1859e39c5baSBill Taylor void
hermon_kstat_fini(hermon_state_t * state)1869e39c5baSBill Taylor hermon_kstat_fini(hermon_state_t *state)
1879e39c5baSBill Taylor {
188d1a5c838SRamaswamy Tummala 	hermon_ks_info_t	*ksi;
1899e39c5baSBill Taylor 	uint_t			numports;
1909e39c5baSBill Taylor 	int			i;
1919e39c5baSBill Taylor 
1929e39c5baSBill Taylor 	/* Get pointer to kstat info */
1939e39c5baSBill Taylor 	ksi = state->hs_ks_info;
1949e39c5baSBill Taylor 
195d1a5c838SRamaswamy Tummala 	/*
196d1a5c838SRamaswamy Tummala 	 * Signal the perfcntr64_update_thread to exit and wait until the
197d1a5c838SRamaswamy Tummala 	 * thread exits.
198d1a5c838SRamaswamy Tummala 	 */
199d1a5c838SRamaswamy Tummala 	mutex_enter(&ksi->hki_perfcntr64_lock);
200d1a5c838SRamaswamy Tummala 	hermon_kstat_perfcntr64_thread_exit(ksi);
201d1a5c838SRamaswamy Tummala 	mutex_exit(&ksi->hki_perfcntr64_lock);
202d1a5c838SRamaswamy Tummala 
203d1a5c838SRamaswamy Tummala 	/* Delete all the "pic" and perfcntr64 kstats (one per port) */
2049e39c5baSBill Taylor 	numports = state->hs_cfg_profile->cp_num_ports;
2059e39c5baSBill Taylor 	for (i = 0; i < numports; i++) {
2069e39c5baSBill Taylor 		if (ksi->hki_picN_ksp[i] != NULL) {
2079e39c5baSBill Taylor 			kstat_delete(ksi->hki_picN_ksp[i]);
2089e39c5baSBill Taylor 		}
209d1a5c838SRamaswamy Tummala 
210d1a5c838SRamaswamy Tummala 		if (ksi->hki_perfcntr64[i].hki64_ksp != NULL) {
211d1a5c838SRamaswamy Tummala 			kstat_delete(ksi->hki_perfcntr64[i].hki64_ksp);
212d1a5c838SRamaswamy Tummala 		}
2139e39c5baSBill Taylor 	}
2149e39c5baSBill Taylor 
2159e39c5baSBill Taylor 	/* Delete the "counter" kstats (one per port) */
2169e39c5baSBill Taylor 	kstat_delete(ksi->hki_cntr_ksp);
2179e39c5baSBill Taylor 
218d1a5c838SRamaswamy Tummala 	cv_destroy(&ksi->hki_perfcntr64_cv);
219d1a5c838SRamaswamy Tummala 	mutex_destroy(&ksi->hki_perfcntr64_lock);
220d1a5c838SRamaswamy Tummala 
2219e39c5baSBill Taylor 	/* Free the kstat info structure */
2229e39c5baSBill Taylor 	kmem_free(ksi, sizeof (hermon_ks_info_t));
2239e39c5baSBill Taylor }
2249e39c5baSBill Taylor 
2259e39c5baSBill Taylor 
2269e39c5baSBill Taylor /*
2279e39c5baSBill Taylor  * hermon_kstat_picN_create()
2289e39c5baSBill Taylor  *    Context: Only called from attach() path context
2299e39c5baSBill Taylor  */
2309e39c5baSBill Taylor static kstat_t *
hermon_kstat_picN_create(hermon_state_t * state,int num_pic,int num_evt,hermon_ks_mask_t * ev_array)2319e39c5baSBill Taylor hermon_kstat_picN_create(hermon_state_t *state, int num_pic, int num_evt,
2329e39c5baSBill Taylor     hermon_ks_mask_t *ev_array)
2339e39c5baSBill Taylor {
2349e39c5baSBill Taylor 	kstat_t			*picN_ksp;
2359e39c5baSBill Taylor 	struct kstat_named	*pic_named_data;
2369e39c5baSBill Taylor 	int			drv_instance, i;
2379e39c5baSBill Taylor 	char			*drv_name;
2389e39c5baSBill Taylor 	char			pic_name[16];
2399e39c5baSBill Taylor 
2409e39c5baSBill Taylor 	/*
2419e39c5baSBill Taylor 	 * Create the "picN" kstat.  In the steps, below we will attach
2429e39c5baSBill Taylor 	 * all of our named event types to it.
2439e39c5baSBill Taylor 	 */
2449e39c5baSBill Taylor 	drv_name = (char *)ddi_driver_name(state->hs_dip);
2459e39c5baSBill Taylor 	drv_instance = ddi_get_instance(state->hs_dip);
2469e39c5baSBill Taylor 	(void) sprintf(pic_name, "pic%d", num_pic);
2479e39c5baSBill Taylor 	picN_ksp = kstat_create(drv_name, drv_instance, pic_name, "bus",
2480b63ccafSToomas Soome 	    KSTAT_TYPE_NAMED, num_evt, 0);
2499e39c5baSBill Taylor 	if (picN_ksp == NULL) {
2509e39c5baSBill Taylor 		return (NULL);
2519e39c5baSBill Taylor 	}
2529e39c5baSBill Taylor 	pic_named_data = (struct kstat_named *)(picN_ksp->ks_data);
2539e39c5baSBill Taylor 
2549e39c5baSBill Taylor 	/*
2559e39c5baSBill Taylor 	 * Write event names and their associated pcr masks. The last entry
2569e39c5baSBill Taylor 	 * in the array (clear_pic) is added separately below (as its pic
2579e39c5baSBill Taylor 	 * value must be inverted).
2589e39c5baSBill Taylor 	 */
2599e39c5baSBill Taylor 	for (i = 0; i < num_evt - 1; i++) {
2609e39c5baSBill Taylor 		pic_named_data[i].value.ui64 =
2619e39c5baSBill Taylor 		    ((uint64_t)i << (num_pic * HERMON_CNTR_SIZE));
2629e39c5baSBill Taylor 		kstat_named_init(&pic_named_data[i], ev_array[i].ks_evt_name,
2639e39c5baSBill Taylor 		    KSTAT_DATA_UINT64);
2649e39c5baSBill Taylor 	}
2659e39c5baSBill Taylor 
2669e39c5baSBill Taylor 	/* Add the "clear_pic" entry */
2679e39c5baSBill Taylor 	pic_named_data[i].value.ui64 =
2689e39c5baSBill Taylor 	    ~((uint64_t)HERMON_CNTR_MASK << (num_pic * HERMON_CNTR_SIZE));
2699e39c5baSBill Taylor 	kstat_named_init(&pic_named_data[i], ev_array[i].ks_evt_name,
2709e39c5baSBill Taylor 	    KSTAT_DATA_UINT64);
2719e39c5baSBill Taylor 
2729e39c5baSBill Taylor 	/* Install the kstat */
2739e39c5baSBill Taylor 	kstat_install(picN_ksp);
2749e39c5baSBill Taylor 
2759e39c5baSBill Taylor 	return (picN_ksp);
2769e39c5baSBill Taylor }
2779e39c5baSBill Taylor 
2789e39c5baSBill Taylor 
2799e39c5baSBill Taylor /*
2809e39c5baSBill Taylor  * hermon_kstat_cntr_create()
2819e39c5baSBill Taylor  *    Context: Only called from attach() path context
2829e39c5baSBill Taylor  */
2839e39c5baSBill Taylor static kstat_t *
hermon_kstat_cntr_create(hermon_state_t * state,int num_pic,int (* update)(kstat_t *,int))2849e39c5baSBill Taylor hermon_kstat_cntr_create(hermon_state_t *state, int num_pic,
2859e39c5baSBill Taylor     int (*update)(kstat_t *, int))
2869e39c5baSBill Taylor {
2879e39c5baSBill Taylor 	struct kstat		*cntr_ksp;
2889e39c5baSBill Taylor 	struct kstat_named	*cntr_named_data;
2899e39c5baSBill Taylor 	int			drv_instance, i;
2909e39c5baSBill Taylor 	char			*drv_name;
2919e39c5baSBill Taylor 	char			pic_str[16];
2929e39c5baSBill Taylor 
2939e39c5baSBill Taylor 	/*
2949e39c5baSBill Taylor 	 * Create the "counters" kstat.  In the steps, below we will attach
2959e39c5baSBill Taylor 	 * all of our "pic" to it.   Note:  The size of this kstat is
2969e39c5baSBill Taylor 	 * num_pic + 1 because it also contains the "%pcr".
2979e39c5baSBill Taylor 	 */
2989e39c5baSBill Taylor 	drv_name = (char *)ddi_driver_name(state->hs_dip);
2999e39c5baSBill Taylor 	drv_instance = ddi_get_instance(state->hs_dip);
3009e39c5baSBill Taylor 	cntr_ksp = kstat_create(drv_name, drv_instance, "counters", "bus",
3019e39c5baSBill Taylor 	    KSTAT_TYPE_NAMED, num_pic + 1, KSTAT_FLAG_WRITABLE);
3029e39c5baSBill Taylor 	if (cntr_ksp == NULL) {
3039e39c5baSBill Taylor 		return (NULL);
3049e39c5baSBill Taylor 	}
3059e39c5baSBill Taylor 	cntr_named_data = (struct kstat_named *)(cntr_ksp->ks_data);
3069e39c5baSBill Taylor 
3079e39c5baSBill Taylor 	/*
3089e39c5baSBill Taylor 	 * Initialize the named kstats (for the "pcr" and for the
3099e39c5baSBill Taylor 	 * individual "pic" kstats)
3109e39c5baSBill Taylor 	 */
3119e39c5baSBill Taylor 	kstat_named_init(&cntr_named_data[0], "pcr", KSTAT_DATA_UINT64);
3129e39c5baSBill Taylor 	for (i = 0; i < num_pic; i++) {
3139e39c5baSBill Taylor 		(void) sprintf(pic_str, "pic%d", i);
3149e39c5baSBill Taylor 		kstat_named_init(&cntr_named_data[i+1], pic_str,
3159e39c5baSBill Taylor 		    KSTAT_DATA_UINT64);
3169e39c5baSBill Taylor 	}
3179e39c5baSBill Taylor 
3189e39c5baSBill Taylor 	/*
3199e39c5baSBill Taylor 	 * Store the Hermon softstate pointer in the kstat's private field so
3209e39c5baSBill Taylor 	 * that it is available to the update function.
3219e39c5baSBill Taylor 	 */
3229e39c5baSBill Taylor 	cntr_ksp->ks_private = (void *)state;
3239e39c5baSBill Taylor 	cntr_ksp->ks_update  = update;
3249e39c5baSBill Taylor 
3259e39c5baSBill Taylor 	/* Install the kstat */
3269e39c5baSBill Taylor 	kstat_install(cntr_ksp);
3279e39c5baSBill Taylor 
3289e39c5baSBill Taylor 	return (cntr_ksp);
3299e39c5baSBill Taylor }
3309e39c5baSBill Taylor 
3319e39c5baSBill Taylor 
3329e39c5baSBill Taylor /*
3339e39c5baSBill Taylor  * hermon_kstat_cntr_update()
3349e39c5baSBill Taylor  *    Context: Called from the kstat context
3359e39c5baSBill Taylor  */
3369e39c5baSBill Taylor static int
hermon_kstat_cntr_update(kstat_t * ksp,int rw)3379e39c5baSBill Taylor hermon_kstat_cntr_update(kstat_t *ksp, int rw)
3389e39c5baSBill Taylor {
3399e39c5baSBill Taylor 	hermon_state_t		*state;
3409e39c5baSBill Taylor 	hermon_ks_mask_t		*ib_perf;
3419e39c5baSBill Taylor 	hermon_ks_info_t		*ksi;
3429e39c5baSBill Taylor 	struct kstat_named	*data;
3439e39c5baSBill Taylor 	uint64_t		pcr;
3449e39c5baSBill Taylor 	uint32_t		tmp;
3459e39c5baSBill Taylor 	uint32_t		oldval;
3469e39c5baSBill Taylor 	uint_t			numports, indx;
3479e39c5baSBill Taylor 	int			status;
3489e39c5baSBill Taylor 	hermon_hw_sm_perfcntr_t	sm_perfcntr;
3499e39c5baSBill Taylor 
3509e39c5baSBill Taylor 	/*
3519e39c5baSBill Taylor 	 * Extract the Hermon softstate pointer, kstat data, pointer to the
3529e39c5baSBill Taylor 	 * kstat info structure, and pointer to the hki_ib_perfcnt[] array
3539e39c5baSBill Taylor 	 * from the input parameters.  Note: For warlock purposes, these
3549e39c5baSBill Taylor 	 * parameters are all accessed only in this routine and are,
3559e39c5baSBill Taylor 	 * therefore, protected by the lock used by the kstat framework.
3569e39c5baSBill Taylor 	 */
3579e39c5baSBill Taylor 	state	= ksp->ks_private;
3589e39c5baSBill Taylor 	data	= (struct kstat_named *)(ksp->ks_data);
3599e39c5baSBill Taylor 	ksi	= state->hs_ks_info;
3609e39c5baSBill Taylor 	ib_perf = &ksi->hki_ib_perfcnt[0];
3619e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ksi))
3629e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
3639e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ib_perf))
3649e39c5baSBill Taylor 
3659e39c5baSBill Taylor 	/*
3669e39c5baSBill Taylor 	 * Depending on whether we are reading the "pic" counters or
3679e39c5baSBill Taylor 	 * writing the "pcr" control register, we need to handle and
3689e39c5baSBill Taylor 	 * fill in the kstat data appropriately.
3699e39c5baSBill Taylor 	 *
3709e39c5baSBill Taylor 	 * If this is a write to the "pcr", then extract the value from
3719e39c5baSBill Taylor 	 * the kstat data and store it in the kstat info structure.
3729e39c5baSBill Taylor 	 *
3739e39c5baSBill Taylor 	 * Otherwise, if this is a read of the "pic" counter(s), then
3749e39c5baSBill Taylor 	 * extract the register offset, size, and mask values from the
3759e39c5baSBill Taylor 	 * ib_perf[] array.  Then read the corresponding register and store
3769e39c5baSBill Taylor 	 * it into the kstat data.  Note:  We only read/fill in pic1 if more
3779e39c5baSBill Taylor 	 * than one port is configured.
3789e39c5baSBill Taylor 	 */
3799e39c5baSBill Taylor 	numports = state->hs_cfg_profile->cp_num_ports;
3809e39c5baSBill Taylor 	if (rw == KSTAT_WRITE) {
3819e39c5baSBill Taylor 		/* Update the stored "pcr" value */
3829e39c5baSBill Taylor 		ksi->hki_pcr = data[0].value.ui64;
3839e39c5baSBill Taylor 		return (0);
3849e39c5baSBill Taylor 	} else {
3859e39c5baSBill Taylor 		/*
3869e39c5baSBill Taylor 		 * Get the current "pcr" value and extract the lower
3879e39c5baSBill Taylor 		 * portion (corresponding to the counters for "pic0")
3889e39c5baSBill Taylor 		 */
3899e39c5baSBill Taylor 		pcr  = ksi->hki_pcr;
3909e39c5baSBill Taylor 		indx = pcr & HERMON_CNTR_MASK;
3919e39c5baSBill Taylor 		data[0].value.ui64 = pcr;
3929e39c5baSBill Taylor 
3939e39c5baSBill Taylor 		/*
3949e39c5baSBill Taylor 		 * Fill in the "pic0" counter, corresponding to port 1.
3959e39c5baSBill Taylor 		 * This involves reading in the current value in the register
3969e39c5baSBill Taylor 		 * and calculating how many events have happened since this
3979e39c5baSBill Taylor 		 * register was last polled.  Then we save away the current
3989e39c5baSBill Taylor 		 * value for the counter and increment the "pic0" total by
3999e39c5baSBill Taylor 		 * the number of new events.
4009e39c5baSBill Taylor 		 */
4019e39c5baSBill Taylor 		oldval = ib_perf[indx].ks_old_pic0;
4029e39c5baSBill Taylor 
4039e39c5baSBill Taylor 		status = hermon_getperfcntr_cmd_post(state, 1,
404d1a5c838SRamaswamy Tummala 		    HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
4059e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
4069e39c5baSBill Taylor 			return (-1);
4079e39c5baSBill Taylor 		}
4089e39c5baSBill Taylor 		switch (indx) {
4099e39c5baSBill Taylor 		case 0:		/* port_xmit_data */
4109e39c5baSBill Taylor 			tmp = sm_perfcntr.portxmdata;
4119e39c5baSBill Taylor 			break;
4129e39c5baSBill Taylor 		case 1:		/* port_recv_data */
4139e39c5baSBill Taylor 			tmp = sm_perfcntr.portrcdata;
4149e39c5baSBill Taylor 			break;
4159e39c5baSBill Taylor 		case 2:		/* port_xmit_pkts */
4169e39c5baSBill Taylor 			tmp = sm_perfcntr.portxmpkts;
4179e39c5baSBill Taylor 			break;
4189e39c5baSBill Taylor 		case 3:		/* port_recv_pkts */
4199e39c5baSBill Taylor 			tmp = sm_perfcntr.portrcpkts;
4209e39c5baSBill Taylor 			break;
4219e39c5baSBill Taylor 		case 4:		/* port_recv_err */
4229e39c5baSBill Taylor 			tmp = sm_perfcntr.portrcv;
4239e39c5baSBill Taylor 			break;
4249e39c5baSBill Taylor 		case 5:		/* port_xmit_discards */
4259e39c5baSBill Taylor 			tmp = sm_perfcntr.portxmdiscard;
4269e39c5baSBill Taylor 			break;
4279e39c5baSBill Taylor 		case 6:		/* vl15_dropped */
4289e39c5baSBill Taylor 			tmp = sm_perfcntr.vl15drop;
4299e39c5baSBill Taylor 			break;
4309e39c5baSBill Taylor 		case 7:		/* port_xmit_wait */
4319e39c5baSBill Taylor 			tmp = sm_perfcntr.portxmwait;
4329e39c5baSBill Taylor 			break;
4339e39c5baSBill Taylor 		case 8:		/* port_recv_remote_phys_err */
4349e39c5baSBill Taylor 			tmp = sm_perfcntr.portrcvrem;
4359e39c5baSBill Taylor 			break;
4369e39c5baSBill Taylor 		case 9:		/* port_xmit_constraint_err */
4379e39c5baSBill Taylor 			tmp = sm_perfcntr.portxmconstr;
4389e39c5baSBill Taylor 			break;
4399e39c5baSBill Taylor 		case 10:	/* port_recv_constraint_err */
4409e39c5baSBill Taylor 			tmp = sm_perfcntr.portrcconstr;
4419e39c5baSBill Taylor 			break;
4429e39c5baSBill Taylor 		case 11:	/* symbol_err_counter */
4439e39c5baSBill Taylor 			tmp = sm_perfcntr.symerr;
4449e39c5baSBill Taylor 			break;
4459e39c5baSBill Taylor 		case 12:	/* link_err_recovery_cnt */
4469e39c5baSBill Taylor 			tmp = sm_perfcntr.linkerrrec;
4479e39c5baSBill Taylor 			break;
4489e39c5baSBill Taylor 		case 13:	/* link_downed_cnt */
4499e39c5baSBill Taylor 			tmp = sm_perfcntr.linkdown;
4509e39c5baSBill Taylor 			break;
4519e39c5baSBill Taylor 		case 14:	/* excessive_buffer_overruns */
4529e39c5baSBill Taylor 			tmp = sm_perfcntr.xsbuffovrun;
4539e39c5baSBill Taylor 			break;
4549e39c5baSBill Taylor 		case 15:	/* local_link_integrity_err */
4559e39c5baSBill Taylor 			tmp = sm_perfcntr.locallinkint;
4569e39c5baSBill Taylor 			break;
4579e39c5baSBill Taylor 		case 16:	/* clear_pic */
4589e39c5baSBill Taylor 			tmp = 0;	/* XXX */
4599e39c5baSBill Taylor 			break;
4609e39c5baSBill Taylor 		default:
4619e39c5baSBill Taylor 			cmn_err(CE_CONT, "perf counter out of range\n");
4629e39c5baSBill Taylor 		}
4639e39c5baSBill Taylor 
4649e39c5baSBill Taylor 		ib_perf[indx].ks_old_pic0 = tmp;
4659e39c5baSBill Taylor 
4669e39c5baSBill Taylor 		tmp = tmp - oldval;
4679e39c5baSBill Taylor 		ksi->hki_pic0 += tmp;
4689e39c5baSBill Taylor 		data[1].value.ui64 = ksi->hki_pic0;
4699e39c5baSBill Taylor 
4709e39c5baSBill Taylor 		/*
4719e39c5baSBill Taylor 		 * If necessary, fill in the "pic1" counter for port 2.
4729e39c5baSBill Taylor 		 * This works the same as above except that we extract the
4739e39c5baSBill Taylor 		 * upper bits (corresponding to the counters for "pic1")
4749e39c5baSBill Taylor 		 */
4759e39c5baSBill Taylor 		if (numports == HERMON_MAX_PORTS) {
4769e39c5baSBill Taylor 			indx   = pcr >> HERMON_CNTR_SIZE;
4779e39c5baSBill Taylor 			oldval = ib_perf[indx].ks_old_pic1;
4789e39c5baSBill Taylor 
4799e39c5baSBill Taylor 			status = hermon_getperfcntr_cmd_post(state, 2,
480d1a5c838SRamaswamy Tummala 			    HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
4819e39c5baSBill Taylor 			if (status != HERMON_CMD_SUCCESS) {
4829e39c5baSBill Taylor 				return (-1);
4839e39c5baSBill Taylor 			}
4849e39c5baSBill Taylor 			switch (indx) {
4859e39c5baSBill Taylor 			case 0:		/* port_xmit_data */
4869e39c5baSBill Taylor 				tmp = sm_perfcntr.portxmdata;
4879e39c5baSBill Taylor 				break;
4889e39c5baSBill Taylor 			case 1:		/* port_recv_data */
4899e39c5baSBill Taylor 				tmp = sm_perfcntr.portrcdata;
4909e39c5baSBill Taylor 				break;
4919e39c5baSBill Taylor 			case 2:		/* port_xmit_pkts */
4929e39c5baSBill Taylor 				tmp = sm_perfcntr.portxmpkts;
4939e39c5baSBill Taylor 				break;
4949e39c5baSBill Taylor 			case 3:		/* port_recv_pkts */
4959e39c5baSBill Taylor 				tmp = sm_perfcntr.portrcpkts;
4969e39c5baSBill Taylor 				break;
4979e39c5baSBill Taylor 			case 4:		/* port_recv_err */
4989e39c5baSBill Taylor 				tmp = sm_perfcntr.portrcv;
4999e39c5baSBill Taylor 				break;
5009e39c5baSBill Taylor 			case 5:		/* port_xmit_discards */
5019e39c5baSBill Taylor 				tmp = sm_perfcntr.portxmdiscard;
5029e39c5baSBill Taylor 				break;
5039e39c5baSBill Taylor 			case 6:		/* vl15_dropped */
5049e39c5baSBill Taylor 				tmp = sm_perfcntr.vl15drop;
5059e39c5baSBill Taylor 				break;
5069e39c5baSBill Taylor 			case 7:		/* port_xmit_wait */
5079e39c5baSBill Taylor 				tmp = sm_perfcntr.portxmwait;
5089e39c5baSBill Taylor 				break;
5099e39c5baSBill Taylor 			case 8:		/* port_recv_remote_phys_err */
5109e39c5baSBill Taylor 				tmp = sm_perfcntr.portrcvrem;
5119e39c5baSBill Taylor 				break;
5129e39c5baSBill Taylor 			case 9:		/* port_xmit_constraint_err */
5139e39c5baSBill Taylor 				tmp = sm_perfcntr.portxmconstr;
5149e39c5baSBill Taylor 				break;
5159e39c5baSBill Taylor 			case 10:	/* port_recv_constraint_err */
5169e39c5baSBill Taylor 				tmp = sm_perfcntr.portrcconstr;
5179e39c5baSBill Taylor 				break;
5189e39c5baSBill Taylor 			case 11:	/* symbol_err_counter */
5199e39c5baSBill Taylor 				tmp = sm_perfcntr.symerr;
5209e39c5baSBill Taylor 				break;
5219e39c5baSBill Taylor 			case 12:	/* link_err_recovery_cnt */
5229e39c5baSBill Taylor 				tmp = sm_perfcntr.linkerrrec;
5239e39c5baSBill Taylor 				break;
5249e39c5baSBill Taylor 			case 13:	/* link_downed_cnt */
5259e39c5baSBill Taylor 				tmp = sm_perfcntr.linkdown;
5269e39c5baSBill Taylor 				break;
5279e39c5baSBill Taylor 			case 14:	/* excessive_buffer_overruns */
5289e39c5baSBill Taylor 				tmp = sm_perfcntr.xsbuffovrun;
5299e39c5baSBill Taylor 				break;
5309e39c5baSBill Taylor 			case 15:	/* local_link_integrity_err */
5319e39c5baSBill Taylor 				tmp = sm_perfcntr.locallinkint;
5329e39c5baSBill Taylor 				break;
5339e39c5baSBill Taylor 			case 16:	/* clear_pic */
5349e39c5baSBill Taylor 				tmp = 0;	/* XXX */
5359e39c5baSBill Taylor 				break;
5369e39c5baSBill Taylor 			default:
5379e39c5baSBill Taylor 				cmn_err(CE_CONT, "perf counter out of range\n");
5389e39c5baSBill Taylor 			}
5399e39c5baSBill Taylor 
5409e39c5baSBill Taylor 			ib_perf[indx].ks_old_pic1 = tmp;
5419e39c5baSBill Taylor 
5429e39c5baSBill Taylor 			tmp = tmp - oldval;
5439e39c5baSBill Taylor 			ksi->hki_pic1 += tmp;
5449e39c5baSBill Taylor 			data[2].value.ui64 = ksi->hki_pic1;
5459e39c5baSBill Taylor 		}
5469e39c5baSBill Taylor 
5479e39c5baSBill Taylor 		return (0);
5489e39c5baSBill Taylor 	}
5499e39c5baSBill Taylor }
550d1a5c838SRamaswamy Tummala 
551d1a5c838SRamaswamy Tummala /*
552d1a5c838SRamaswamy Tummala  * 64 bit kstats for performance counters:
553d1a5c838SRamaswamy Tummala  *
55430e01c53SRamaswamy Tummala  * Export 64 bit performance counters in kstats.
55530e01c53SRamaswamy Tummala  *
55630e01c53SRamaswamy Tummala  * If the HCA hardware supports 64 bit extended port counters, we use the
55730e01c53SRamaswamy Tummala  * hardware based counters. If the HCA hardware does not support extended port
55830e01c53SRamaswamy Tummala  * counters, we maintain 64 bit performance counters in software using the
55930e01c53SRamaswamy Tummala  * 32 bit hardware port counters.
56030e01c53SRamaswamy Tummala  *
56130e01c53SRamaswamy Tummala  * The software based counters are maintained as follows:
562d1a5c838SRamaswamy Tummala  *
563d1a5c838SRamaswamy Tummala  * We create a thread that, every one second, reads the values of 32 bit
564d1a5c838SRamaswamy Tummala  * hardware counters and adds them to the 64 bit software counters. Immediately
565d1a5c838SRamaswamy Tummala  * after reading, it resets the 32 bit hardware counters to zero (so that they
566d1a5c838SRamaswamy Tummala  * start counting from zero again). At any time the current value of a counter
567d1a5c838SRamaswamy Tummala  * is going to be the sum of the 64 bit software counter and the 32 bit
568d1a5c838SRamaswamy Tummala  * hardware counter.
569d1a5c838SRamaswamy Tummala  *
570d1a5c838SRamaswamy Tummala  * Since this work need not be done if there is no consumer, by default
571d1a5c838SRamaswamy Tummala  * we do not maintain 64 bit software counters. To enable this the consumer
572d1a5c838SRamaswamy Tummala  * needs to write a non-zero value to the "enable" component of the of
573d1a5c838SRamaswamy Tummala  * perf_counters kstat. Writing zero to this component will disable this work.
57430e01c53SRamaswamy Tummala  * NOTE: The enabling or disabling applies to software based counters only.
57530e01c53SRamaswamy Tummala  * Hardware based counters counters are always enabled.
576d1a5c838SRamaswamy Tummala  *
577d1a5c838SRamaswamy Tummala  * If performance monitor is enabled in subnet manager, the SM could
578d1a5c838SRamaswamy Tummala  * periodically reset the hardware counters by sending perf-MADs. So only
579d1a5c838SRamaswamy Tummala  * one of either our software 64 bit counters or the SM performance monitor
580d1a5c838SRamaswamy Tummala  * could be enabled at the same time. However, if both of them are enabled at
581d1a5c838SRamaswamy Tummala  * the same time we still do our best by keeping track of the values of the
582d1a5c838SRamaswamy Tummala  * last read 32 bit hardware counters. If the current read of a 32 bit hardware
583d1a5c838SRamaswamy Tummala  * counter is less than the last read of the counter, we ignore the current
584d1a5c838SRamaswamy Tummala  * value and go with the last read value.
585d1a5c838SRamaswamy Tummala  */
586d1a5c838SRamaswamy Tummala 
587d1a5c838SRamaswamy Tummala /*
588d1a5c838SRamaswamy Tummala  * hermon_kstat_perfcntr64_create()
589d1a5c838SRamaswamy Tummala  *    Context: Only called from attach() path context
590d1a5c838SRamaswamy Tummala  *
591d1a5c838SRamaswamy Tummala  * Create "port#/perf_counters" kstat for the specified port number.
592d1a5c838SRamaswamy Tummala  */
593d1a5c838SRamaswamy Tummala void
hermon_kstat_perfcntr64_create(hermon_state_t * state,uint_t port_num)594d1a5c838SRamaswamy Tummala hermon_kstat_perfcntr64_create(hermon_state_t *state, uint_t port_num)
595d1a5c838SRamaswamy Tummala {
596d1a5c838SRamaswamy Tummala 	hermon_ks_info_t	*ksi = state->hs_ks_info;
597d1a5c838SRamaswamy Tummala 	struct kstat		*cntr_ksp;
598d1a5c838SRamaswamy Tummala 	struct kstat_named	*cntr_named_data;
599d1a5c838SRamaswamy Tummala 	int			drv_instance;
600d1a5c838SRamaswamy Tummala 	char			*drv_name;
601d1a5c838SRamaswamy Tummala 	char			kname[32];
60230e01c53SRamaswamy Tummala 	int			status, ext_width_supported;
603d1a5c838SRamaswamy Tummala 
604d1a5c838SRamaswamy Tummala 	ASSERT(port_num != 0);
605d1a5c838SRamaswamy Tummala 
60630e01c53SRamaswamy Tummala 	status = hermon_is_ext_port_counters_supported(state, port_num,
60730e01c53SRamaswamy Tummala 	    HERMON_CMD_NOSLEEP_SPIN, &ext_width_supported);
60830e01c53SRamaswamy Tummala 	if (status == HERMON_CMD_SUCCESS) {
60930e01c53SRamaswamy Tummala 		ksi->hki_perfcntr64[port_num - 1].
61030e01c53SRamaswamy Tummala 		    hki64_ext_port_counters_supported = ext_width_supported;
61130e01c53SRamaswamy Tummala 	}
61230e01c53SRamaswamy Tummala 
613d1a5c838SRamaswamy Tummala 	drv_name = (char *)ddi_driver_name(state->hs_dip);
614d1a5c838SRamaswamy Tummala 	drv_instance = ddi_get_instance(state->hs_dip);
615d1a5c838SRamaswamy Tummala 	(void) snprintf(kname, sizeof (kname), "port%u/perf_counters",
616d1a5c838SRamaswamy Tummala 	    port_num);
617d1a5c838SRamaswamy Tummala 	cntr_ksp = kstat_create(drv_name, drv_instance, kname, "ib",
618d1a5c838SRamaswamy Tummala 	    KSTAT_TYPE_NAMED, HERMON_PERFCNTR64_NUM_COUNTERS,
619d1a5c838SRamaswamy Tummala 	    KSTAT_FLAG_WRITABLE);
620d1a5c838SRamaswamy Tummala 	if (cntr_ksp == NULL) {
621d1a5c838SRamaswamy Tummala 		return;
622d1a5c838SRamaswamy Tummala 	}
623d1a5c838SRamaswamy Tummala 	cntr_named_data = (struct kstat_named *)(cntr_ksp->ks_data);
624d1a5c838SRamaswamy Tummala 
625d1a5c838SRamaswamy Tummala 	kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_ENABLE_IDX],
626d1a5c838SRamaswamy Tummala 	    "enable", KSTAT_DATA_UINT32);
627d1a5c838SRamaswamy Tummala 	kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_XMIT_DATA_IDX],
628d1a5c838SRamaswamy Tummala 	    "xmit_data", KSTAT_DATA_UINT64);
629d1a5c838SRamaswamy Tummala 	kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_RECV_DATA_IDX],
630d1a5c838SRamaswamy Tummala 	    "recv_data", KSTAT_DATA_UINT64);
631d1a5c838SRamaswamy Tummala 	kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_XMIT_PKTS_IDX],
632d1a5c838SRamaswamy Tummala 	    "xmit_pkts", KSTAT_DATA_UINT64);
633d1a5c838SRamaswamy Tummala 	kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_RECV_PKTS_IDX],
634d1a5c838SRamaswamy Tummala 	    "recv_pkts", KSTAT_DATA_UINT64);
635d1a5c838SRamaswamy Tummala 
636d1a5c838SRamaswamy Tummala 	ksi->hki_perfcntr64[port_num - 1].hki64_ksp = cntr_ksp;
637d1a5c838SRamaswamy Tummala 	ksi->hki_perfcntr64[port_num - 1].hki64_port_num = port_num;
638d1a5c838SRamaswamy Tummala 	ksi->hki_perfcntr64[port_num - 1].hki64_state = state;
639d1a5c838SRamaswamy Tummala 
640d1a5c838SRamaswamy Tummala 	cntr_ksp->ks_private = &ksi->hki_perfcntr64[port_num - 1];
641d1a5c838SRamaswamy Tummala 	cntr_ksp->ks_update  = hermon_kstat_perfcntr64_update;
642d1a5c838SRamaswamy Tummala 
643d1a5c838SRamaswamy Tummala 	/* Install the kstat */
644d1a5c838SRamaswamy Tummala 	kstat_install(cntr_ksp);
645d1a5c838SRamaswamy Tummala }
646d1a5c838SRamaswamy Tummala 
647d1a5c838SRamaswamy Tummala /*
648d1a5c838SRamaswamy Tummala  * hermon_kstat_perfcntr64_read()
649d1a5c838SRamaswamy Tummala  *
650d1a5c838SRamaswamy Tummala  * Read the values of 32 bit hardware counters.
651d1a5c838SRamaswamy Tummala  *
652d1a5c838SRamaswamy Tummala  * If reset is true, reset the 32 bit hardware counters. Add the values of the
653d1a5c838SRamaswamy Tummala  * 32 bit hardware counters to the 64 bit software counters.
654d1a5c838SRamaswamy Tummala  *
655d1a5c838SRamaswamy Tummala  * If reset is false, just save the values read from the 32 bit hardware
656d1a5c838SRamaswamy Tummala  * counters in hki64_last_read[].
657d1a5c838SRamaswamy Tummala  *
658d1a5c838SRamaswamy Tummala  * See the general comment on the 64 bit performance counters
659d1a5c838SRamaswamy Tummala  * regarding the use of last read 32 bit hardware counter values.
660d1a5c838SRamaswamy Tummala  */
661d1a5c838SRamaswamy Tummala static int
hermon_kstat_perfcntr64_read(hermon_state_t * state,uint_t port,int reset)662d1a5c838SRamaswamy Tummala hermon_kstat_perfcntr64_read(hermon_state_t *state, uint_t port, int reset)
663d1a5c838SRamaswamy Tummala {
664d1a5c838SRamaswamy Tummala 	hermon_ks_info_t	*ksi = state->hs_ks_info;
665d1a5c838SRamaswamy Tummala 	hermon_perfcntr64_ks_info_t *ksi64 = &ksi->hki_perfcntr64[port - 1];
666d1a5c838SRamaswamy Tummala 	int			status, i;
667d1a5c838SRamaswamy Tummala 	uint32_t		tmp;
668d1a5c838SRamaswamy Tummala 	hermon_hw_sm_perfcntr_t	sm_perfcntr;
669d1a5c838SRamaswamy Tummala 
670d1a5c838SRamaswamy Tummala 	ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock));
671d1a5c838SRamaswamy Tummala 	ASSERT(port != 0);
672d1a5c838SRamaswamy Tummala 
673d1a5c838SRamaswamy Tummala 	/* read the 32 bit hardware counters */
674d1a5c838SRamaswamy Tummala 	status = hermon_getperfcntr_cmd_post(state, port,
675d1a5c838SRamaswamy Tummala 	    HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
676d1a5c838SRamaswamy Tummala 	if (status != HERMON_CMD_SUCCESS) {
677d1a5c838SRamaswamy Tummala 		return (status);
678d1a5c838SRamaswamy Tummala 	}
679d1a5c838SRamaswamy Tummala 
680d1a5c838SRamaswamy Tummala 	if (reset) {
681d1a5c838SRamaswamy Tummala 		/* reset the hardware counters */
682d1a5c838SRamaswamy Tummala 		status = hermon_getperfcntr_cmd_post(state, port,
683d1a5c838SRamaswamy Tummala 		    HERMON_CMD_NOSLEEP_SPIN, NULL, 1);
684d1a5c838SRamaswamy Tummala 		if (status != HERMON_CMD_SUCCESS) {
685d1a5c838SRamaswamy Tummala 			return (status);
686d1a5c838SRamaswamy Tummala 		}
687d1a5c838SRamaswamy Tummala 
688d1a5c838SRamaswamy Tummala 		/*
689d1a5c838SRamaswamy Tummala 		 * Update 64 bit software counters
690d1a5c838SRamaswamy Tummala 		 */
691d1a5c838SRamaswamy Tummala 		tmp = MAX(sm_perfcntr.portxmdata,
692d1a5c838SRamaswamy Tummala 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX]);
693d1a5c838SRamaswamy Tummala 		ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_DATA_IDX] += tmp;
694d1a5c838SRamaswamy Tummala 
695d1a5c838SRamaswamy Tummala 		tmp = MAX(sm_perfcntr.portrcdata,
696d1a5c838SRamaswamy Tummala 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX]);
697d1a5c838SRamaswamy Tummala 		ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_DATA_IDX] += tmp;
698d1a5c838SRamaswamy Tummala 
699d1a5c838SRamaswamy Tummala 		tmp = MAX(sm_perfcntr.portxmpkts,
700d1a5c838SRamaswamy Tummala 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX]);
701d1a5c838SRamaswamy Tummala 		ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_PKTS_IDX] += tmp;
702d1a5c838SRamaswamy Tummala 
703d1a5c838SRamaswamy Tummala 		tmp = MAX(sm_perfcntr.portrcpkts,
704d1a5c838SRamaswamy Tummala 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX]);
705d1a5c838SRamaswamy Tummala 		ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_PKTS_IDX] += tmp;
706d1a5c838SRamaswamy Tummala 
707d1a5c838SRamaswamy Tummala 		for (i = 0; i < HERMON_PERFCNTR64_NUM_COUNTERS; i++)
708d1a5c838SRamaswamy Tummala 			ksi64->hki64_last_read[i] = 0;
709d1a5c838SRamaswamy Tummala 
710d1a5c838SRamaswamy Tummala 	} else {
711d1a5c838SRamaswamy Tummala 		/*
712d1a5c838SRamaswamy Tummala 		 * Update ksi64->hki64_last_read[]
713d1a5c838SRamaswamy Tummala 		 */
714d1a5c838SRamaswamy Tummala 		SET_TO_MAX(
715d1a5c838SRamaswamy Tummala 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX],
716d1a5c838SRamaswamy Tummala 		    sm_perfcntr.portxmdata);
717d1a5c838SRamaswamy Tummala 
718d1a5c838SRamaswamy Tummala 		SET_TO_MAX(
719d1a5c838SRamaswamy Tummala 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX],
720d1a5c838SRamaswamy Tummala 		    sm_perfcntr.portrcdata);
721d1a5c838SRamaswamy Tummala 
722d1a5c838SRamaswamy Tummala 		SET_TO_MAX(
723d1a5c838SRamaswamy Tummala 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX],
724d1a5c838SRamaswamy Tummala 		    sm_perfcntr.portxmpkts);
725d1a5c838SRamaswamy Tummala 
726d1a5c838SRamaswamy Tummala 		SET_TO_MAX(
727d1a5c838SRamaswamy Tummala 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX],
728d1a5c838SRamaswamy Tummala 		    sm_perfcntr.portrcpkts);
729d1a5c838SRamaswamy Tummala 	}
730d1a5c838SRamaswamy Tummala 
731d1a5c838SRamaswamy Tummala 	return (HERMON_CMD_SUCCESS);
732d1a5c838SRamaswamy Tummala }
733d1a5c838SRamaswamy Tummala 
734d1a5c838SRamaswamy Tummala /*
735d1a5c838SRamaswamy Tummala  * hermon_kstat_perfcntr64_update_thread()
736d1a5c838SRamaswamy Tummala  *    Context: Entry point for a kernel thread
737d1a5c838SRamaswamy Tummala  *
738d1a5c838SRamaswamy Tummala  * Maintain 64 bit performance counters in software using the 32 bit
739d1a5c838SRamaswamy Tummala  * hardware counters.
740d1a5c838SRamaswamy Tummala  */
741d1a5c838SRamaswamy Tummala static void
hermon_kstat_perfcntr64_update_thread(void * arg)742d1a5c838SRamaswamy Tummala hermon_kstat_perfcntr64_update_thread(void *arg)
743d1a5c838SRamaswamy Tummala {
744d1a5c838SRamaswamy Tummala 	hermon_state_t		*state = (hermon_state_t *)arg;
745d1a5c838SRamaswamy Tummala 	hermon_ks_info_t	*ksi = state->hs_ks_info;
746d1a5c838SRamaswamy Tummala 	uint_t			i;
747d3d50737SRafael Vanoni 	clock_t			delta = drv_usectohz(1000000);
748d1a5c838SRamaswamy Tummala 
749d1a5c838SRamaswamy Tummala 	mutex_enter(&ksi->hki_perfcntr64_lock);
750d1a5c838SRamaswamy Tummala 	/*
751d1a5c838SRamaswamy Tummala 	 * Every one second update the values 64 bit software counters
752d1a5c838SRamaswamy Tummala 	 * for all ports. Exit if HERMON_PERFCNTR64_THREAD_EXIT flag is set.
753d1a5c838SRamaswamy Tummala 	 */
754d1a5c838SRamaswamy Tummala 	while (!(ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_EXIT)) {
755d1a5c838SRamaswamy Tummala 		for (i = 0; i < state->hs_cfg_profile->cp_num_ports; i++) {
756d1a5c838SRamaswamy Tummala 			if (ksi->hki_perfcntr64[i].hki64_enabled) {
757d1a5c838SRamaswamy Tummala 				(void) hermon_kstat_perfcntr64_read(state,
758d1a5c838SRamaswamy Tummala 				    i + 1, 1);
759d1a5c838SRamaswamy Tummala 			}
760d1a5c838SRamaswamy Tummala 		}
761d1a5c838SRamaswamy Tummala 		/* sleep for a second */
762d3d50737SRafael Vanoni 		(void) cv_reltimedwait(&ksi->hki_perfcntr64_cv,
763d3d50737SRafael Vanoni 		    &ksi->hki_perfcntr64_lock, delta, TR_CLOCK_TICK);
764d1a5c838SRamaswamy Tummala 	}
765d1a5c838SRamaswamy Tummala 	ksi->hki_perfcntr64_flags = 0;
766d1a5c838SRamaswamy Tummala 	mutex_exit(&ksi->hki_perfcntr64_lock);
767d1a5c838SRamaswamy Tummala }
768d1a5c838SRamaswamy Tummala 
769d1a5c838SRamaswamy Tummala /*
770d1a5c838SRamaswamy Tummala  * hermon_kstat_perfcntr64_thread_create()
771d1a5c838SRamaswamy Tummala  *    Context: Called from the kstat context
772d1a5c838SRamaswamy Tummala  *
773d1a5c838SRamaswamy Tummala  * Create a thread that maintains 64 bit performance counters in software.
774d1a5c838SRamaswamy Tummala  */
775d1a5c838SRamaswamy Tummala static void
hermon_kstat_perfcntr64_thread_create(hermon_state_t * state)776d1a5c838SRamaswamy Tummala hermon_kstat_perfcntr64_thread_create(hermon_state_t *state)
777d1a5c838SRamaswamy Tummala {
778d1a5c838SRamaswamy Tummala 	hermon_ks_info_t	*ksi = state->hs_ks_info;
779d1a5c838SRamaswamy Tummala 	kthread_t		*thr;
780d1a5c838SRamaswamy Tummala 
781d1a5c838SRamaswamy Tummala 	ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock));
782d1a5c838SRamaswamy Tummala 
783d1a5c838SRamaswamy Tummala 	/*
784d1a5c838SRamaswamy Tummala 	 * One thread per hermon instance. Don't create a thread if already
785d1a5c838SRamaswamy Tummala 	 * created.
786d1a5c838SRamaswamy Tummala 	 */
787d1a5c838SRamaswamy Tummala 	if (!(ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_CREATED)) {
788d1a5c838SRamaswamy Tummala 		thr = thread_create(NULL, 0,
789d1a5c838SRamaswamy Tummala 		    hermon_kstat_perfcntr64_update_thread,
790d1a5c838SRamaswamy Tummala 		    state, 0, &p0, TS_RUN, minclsyspri);
791d1a5c838SRamaswamy Tummala 		ksi->hki_perfcntr64_thread_id = thr->t_did;
792d1a5c838SRamaswamy Tummala 		ksi->hki_perfcntr64_flags |= HERMON_PERFCNTR64_THREAD_CREATED;
793d1a5c838SRamaswamy Tummala 	}
794d1a5c838SRamaswamy Tummala }
795d1a5c838SRamaswamy Tummala 
796d1a5c838SRamaswamy Tummala /*
797d1a5c838SRamaswamy Tummala  * hermon_kstat_perfcntr64_thread_exit()
798d1a5c838SRamaswamy Tummala  *    Context: Called from attach, detach or kstat context
799d1a5c838SRamaswamy Tummala  */
800d1a5c838SRamaswamy Tummala static void
hermon_kstat_perfcntr64_thread_exit(hermon_ks_info_t * ksi)801d1a5c838SRamaswamy Tummala hermon_kstat_perfcntr64_thread_exit(hermon_ks_info_t *ksi)
802d1a5c838SRamaswamy Tummala {
803d1a5c838SRamaswamy Tummala 	kt_did_t	tid;
804d1a5c838SRamaswamy Tummala 
805d1a5c838SRamaswamy Tummala 	ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock));
806d1a5c838SRamaswamy Tummala 
807d1a5c838SRamaswamy Tummala 	if (ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_CREATED) {
808d1a5c838SRamaswamy Tummala 		/*
809d1a5c838SRamaswamy Tummala 		 * Signal the thread to exit and wait until the thread exits.
810d1a5c838SRamaswamy Tummala 		 */
811d1a5c838SRamaswamy Tummala 		ksi->hki_perfcntr64_flags |= HERMON_PERFCNTR64_THREAD_EXIT;
812d1a5c838SRamaswamy Tummala 		tid = ksi->hki_perfcntr64_thread_id;
813d1a5c838SRamaswamy Tummala 		cv_signal(&ksi->hki_perfcntr64_cv);
814d1a5c838SRamaswamy Tummala 
815d1a5c838SRamaswamy Tummala 		mutex_exit(&ksi->hki_perfcntr64_lock);
816d1a5c838SRamaswamy Tummala 		thread_join(tid);
817d1a5c838SRamaswamy Tummala 		mutex_enter(&ksi->hki_perfcntr64_lock);
818d1a5c838SRamaswamy Tummala 	}
819d1a5c838SRamaswamy Tummala }
820d1a5c838SRamaswamy Tummala 
82130e01c53SRamaswamy Tummala /*
82230e01c53SRamaswamy Tummala  * hermon_kstat_perfcntr64_update_ext()
82330e01c53SRamaswamy Tummala  *    Context: Called from the kstat context
82430e01c53SRamaswamy Tummala  *
82530e01c53SRamaswamy Tummala  * Update perf_counters kstats with the values of the extended port counters
82630e01c53SRamaswamy Tummala  * from the hardware.
82730e01c53SRamaswamy Tummala  */
82830e01c53SRamaswamy Tummala static int
hermon_kstat_perfcntr64_update_ext(hermon_perfcntr64_ks_info_t * ksi64,int rw,struct kstat_named * data)82930e01c53SRamaswamy Tummala hermon_kstat_perfcntr64_update_ext(hermon_perfcntr64_ks_info_t *ksi64, int rw,
83030e01c53SRamaswamy Tummala     struct kstat_named *data)
83130e01c53SRamaswamy Tummala {
83230e01c53SRamaswamy Tummala 	hermon_hw_sm_extperfcntr_t	sm_extperfcntr;
83330e01c53SRamaswamy Tummala 
83430e01c53SRamaswamy Tummala 	/*
83530e01c53SRamaswamy Tummala 	 * The "enable" component of the kstat is the only writable kstat.
83630e01c53SRamaswamy Tummala 	 * It is a no-op when the hardware supports extended port counters.
83730e01c53SRamaswamy Tummala 	 */
83830e01c53SRamaswamy Tummala 	if (rw == KSTAT_WRITE)
83930e01c53SRamaswamy Tummala 		return (0);
84030e01c53SRamaswamy Tummala 
84130e01c53SRamaswamy Tummala 	/*
84230e01c53SRamaswamy Tummala 	 * Read the counters and update kstats.
84330e01c53SRamaswamy Tummala 	 */
84430e01c53SRamaswamy Tummala 	if (hermon_getextperfcntr_cmd_post(ksi64->hki64_state,
84530e01c53SRamaswamy Tummala 	    ksi64->hki64_port_num, HERMON_CMD_NOSLEEP_SPIN, &sm_extperfcntr) !=
84630e01c53SRamaswamy Tummala 	    HERMON_CMD_SUCCESS) {
84730e01c53SRamaswamy Tummala 		return (EIO);
84830e01c53SRamaswamy Tummala 	}
84930e01c53SRamaswamy Tummala 
85030e01c53SRamaswamy Tummala 	data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 1;
85130e01c53SRamaswamy Tummala 
85230e01c53SRamaswamy Tummala 	data[HERMON_PERFCNTR64_XMIT_DATA_IDX].value.ui64 =
85330e01c53SRamaswamy Tummala 	    sm_extperfcntr.portxmdata;
85430e01c53SRamaswamy Tummala 
85530e01c53SRamaswamy Tummala 	data[HERMON_PERFCNTR64_RECV_DATA_IDX].value.ui64 =
85630e01c53SRamaswamy Tummala 	    sm_extperfcntr.portrcdata;
85730e01c53SRamaswamy Tummala 
85830e01c53SRamaswamy Tummala 	data[HERMON_PERFCNTR64_XMIT_PKTS_IDX].value.ui64 =
85930e01c53SRamaswamy Tummala 	    sm_extperfcntr.portxmpkts;
86030e01c53SRamaswamy Tummala 
86130e01c53SRamaswamy Tummala 	data[HERMON_PERFCNTR64_RECV_PKTS_IDX].value.ui64 =
86230e01c53SRamaswamy Tummala 	    sm_extperfcntr.portrcpkts;
86330e01c53SRamaswamy Tummala 
86430e01c53SRamaswamy Tummala 	return (0);
86530e01c53SRamaswamy Tummala }
86630e01c53SRamaswamy Tummala 
867d1a5c838SRamaswamy Tummala /*
868d1a5c838SRamaswamy Tummala  * hermon_kstat_perfcntr64_update()
869d1a5c838SRamaswamy Tummala  *    Context: Called from the kstat context
870d1a5c838SRamaswamy Tummala  *
871d1a5c838SRamaswamy Tummala  * See the general comment on 64 bit kstats for performance counters:
872d1a5c838SRamaswamy Tummala  */
873d1a5c838SRamaswamy Tummala static int
hermon_kstat_perfcntr64_update(kstat_t * ksp,int rw)874d1a5c838SRamaswamy Tummala hermon_kstat_perfcntr64_update(kstat_t *ksp, int rw)
875d1a5c838SRamaswamy Tummala {
876d1a5c838SRamaswamy Tummala 	hermon_state_t			*state;
877d1a5c838SRamaswamy Tummala 	struct kstat_named		*data;
878d1a5c838SRamaswamy Tummala 	hermon_ks_info_t		*ksi;
879d1a5c838SRamaswamy Tummala 	hermon_perfcntr64_ks_info_t	*ksi64;
880d1a5c838SRamaswamy Tummala 	int				i, thr_exit;
88130e01c53SRamaswamy Tummala 	int				rv;
882d1a5c838SRamaswamy Tummala 
883d1a5c838SRamaswamy Tummala 	ksi64	= ksp->ks_private;
884d1a5c838SRamaswamy Tummala 	state	= ksi64->hki64_state;
885d1a5c838SRamaswamy Tummala 	ksi	= state->hs_ks_info;
886d1a5c838SRamaswamy Tummala 	data	= (struct kstat_named *)(ksp->ks_data);
887d1a5c838SRamaswamy Tummala 
888d1a5c838SRamaswamy Tummala 	mutex_enter(&ksi->hki_perfcntr64_lock);
889d1a5c838SRamaswamy Tummala 
89030e01c53SRamaswamy Tummala 	if (ksi64->hki64_ext_port_counters_supported) {
89130e01c53SRamaswamy Tummala 		rv = hermon_kstat_perfcntr64_update_ext(ksi64, rw, data);
89230e01c53SRamaswamy Tummala 		mutex_exit(&ksi->hki_perfcntr64_lock);
89330e01c53SRamaswamy Tummala 		return (rv);
89430e01c53SRamaswamy Tummala 	}
89530e01c53SRamaswamy Tummala 
896d1a5c838SRamaswamy Tummala 	/*
897d1a5c838SRamaswamy Tummala 	 * 64 bit performance counters maintained by the software is not
898d1a5c838SRamaswamy Tummala 	 * enabled by default. Enable them upon a writing a non-zero value
899d1a5c838SRamaswamy Tummala 	 * to "enable" kstat. Disable them upon a writing zero to the
900d1a5c838SRamaswamy Tummala 	 * "enable" kstat.
901d1a5c838SRamaswamy Tummala 	 */
902d1a5c838SRamaswamy Tummala 	if (rw == KSTAT_WRITE) {
903d1a5c838SRamaswamy Tummala 		if (data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32) {
904d1a5c838SRamaswamy Tummala 			if (ksi64->hki64_enabled == 0) {
90560c682e1SRamaswamy Tummala 				/*
90660c682e1SRamaswamy Tummala 				 * Reset the hardware counters to ensure that
90760c682e1SRamaswamy Tummala 				 * the hardware counter doesn't max out
90860c682e1SRamaswamy Tummala 				 * (and hence stop counting) before we get
90960c682e1SRamaswamy Tummala 				 * a chance to reset the counter in
91060c682e1SRamaswamy Tummala 				 * hermon_kstat_perfcntr64_update_thread.
91160c682e1SRamaswamy Tummala 				 */
91260c682e1SRamaswamy Tummala 				if (hermon_getperfcntr_cmd_post(state,
91360c682e1SRamaswamy Tummala 				    ksi64->hki64_port_num,
91460c682e1SRamaswamy Tummala 				    HERMON_CMD_NOSLEEP_SPIN, NULL, 1) !=
91560c682e1SRamaswamy Tummala 				    HERMON_CMD_SUCCESS) {
91660c682e1SRamaswamy Tummala 					mutex_exit(&ksi->hki_perfcntr64_lock);
91760c682e1SRamaswamy Tummala 					return (EIO);
91860c682e1SRamaswamy Tummala 				}
91960c682e1SRamaswamy Tummala 
920d1a5c838SRamaswamy Tummala 				/* Enable 64 bit software counters */
921d1a5c838SRamaswamy Tummala 				ksi64->hki64_enabled = 1;
922d1a5c838SRamaswamy Tummala 				for (i = 0;
923d1a5c838SRamaswamy Tummala 				    i < HERMON_PERFCNTR64_NUM_COUNTERS; i++) {
924d1a5c838SRamaswamy Tummala 					ksi64->hki64_counters[i] = 0;
925d1a5c838SRamaswamy Tummala 					ksi64->hki64_last_read[i] = 0;
926d1a5c838SRamaswamy Tummala 				}
927d1a5c838SRamaswamy Tummala 				hermon_kstat_perfcntr64_thread_create(state);
928d1a5c838SRamaswamy Tummala 			}
929d1a5c838SRamaswamy Tummala 
930d1a5c838SRamaswamy Tummala 		} else if (ksi64->hki64_enabled) {
931d1a5c838SRamaswamy Tummala 			/* Disable 64 bit software counters */
932d1a5c838SRamaswamy Tummala 			ksi64->hki64_enabled = 0;
933d1a5c838SRamaswamy Tummala 			thr_exit = 1;
934d1a5c838SRamaswamy Tummala 			for (i = 0; i < state->hs_cfg_profile->cp_num_ports;
935d1a5c838SRamaswamy Tummala 			    i++) {
936d1a5c838SRamaswamy Tummala 				if (ksi->hki_perfcntr64[i].hki64_enabled) {
937d1a5c838SRamaswamy Tummala 					thr_exit = 0;
938d1a5c838SRamaswamy Tummala 					break;
939d1a5c838SRamaswamy Tummala 				}
940d1a5c838SRamaswamy Tummala 			}
941d1a5c838SRamaswamy Tummala 			if (thr_exit)
942d1a5c838SRamaswamy Tummala 				hermon_kstat_perfcntr64_thread_exit(ksi);
943d1a5c838SRamaswamy Tummala 		}
944d1a5c838SRamaswamy Tummala 	} else if (ksi64->hki64_enabled) {
945d1a5c838SRamaswamy Tummala 		/*
946d1a5c838SRamaswamy Tummala 		 * Read the counters and update kstats.
947d1a5c838SRamaswamy Tummala 		 */
948d1a5c838SRamaswamy Tummala 		if (hermon_kstat_perfcntr64_read(state, ksi64->hki64_port_num,
949d1a5c838SRamaswamy Tummala 		    0) != HERMON_CMD_SUCCESS) {
950d1a5c838SRamaswamy Tummala 			mutex_exit(&ksi->hki_perfcntr64_lock);
951d1a5c838SRamaswamy Tummala 			return (EIO);
952d1a5c838SRamaswamy Tummala 		}
953d1a5c838SRamaswamy Tummala 
95460c682e1SRamaswamy Tummala 		data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 1;
95560c682e1SRamaswamy Tummala 
956d1a5c838SRamaswamy Tummala 		data[HERMON_PERFCNTR64_XMIT_DATA_IDX].value.ui64 =
957d1a5c838SRamaswamy Tummala 		    ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_DATA_IDX] +
958d1a5c838SRamaswamy Tummala 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX];
959d1a5c838SRamaswamy Tummala 
960d1a5c838SRamaswamy Tummala 		data[HERMON_PERFCNTR64_RECV_DATA_IDX].value.ui64 =
961d1a5c838SRamaswamy Tummala 		    ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_DATA_IDX] +
962d1a5c838SRamaswamy Tummala 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX];
963d1a5c838SRamaswamy Tummala 
964d1a5c838SRamaswamy Tummala 		data[HERMON_PERFCNTR64_XMIT_PKTS_IDX].value.ui64 =
965d1a5c838SRamaswamy Tummala 		    ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_PKTS_IDX] +
966d1a5c838SRamaswamy Tummala 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX];
967d1a5c838SRamaswamy Tummala 
968d1a5c838SRamaswamy Tummala 		data[HERMON_PERFCNTR64_RECV_PKTS_IDX].value.ui64 =
969d1a5c838SRamaswamy Tummala 		    ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_PKTS_IDX] +
970d1a5c838SRamaswamy Tummala 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX];
971d1a5c838SRamaswamy Tummala 
972d1a5c838SRamaswamy Tummala 	} else {
973d1a5c838SRamaswamy Tummala 		/* return 0 in kstats if not enabled */
974d1a5c838SRamaswamy Tummala 		data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 0;
975d1a5c838SRamaswamy Tummala 		for (i = 1; i < HERMON_PERFCNTR64_NUM_COUNTERS; i++)
976d1a5c838SRamaswamy Tummala 			data[i].value.ui64 = 0;
977d1a5c838SRamaswamy Tummala 	}
978d1a5c838SRamaswamy Tummala 
979d1a5c838SRamaswamy Tummala 	mutex_exit(&ksi->hki_perfcntr64_lock);
980d1a5c838SRamaswamy Tummala 	return (0);
981d1a5c838SRamaswamy Tummala }
982