xref: /illumos-gate/usr/src/uts/common/io/ib/adapters/tavor/tavor_stats.c (revision 2570281cf351044b6936651ce26dbe1f801dcbd8)
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 /*
23e9dc6bffSRamaswamy Tummala  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
249e39c5baSBill Taylor  * Use is subject to license terms.
259e39c5baSBill Taylor  */
269e39c5baSBill Taylor 
279e39c5baSBill Taylor /*
289e39c5baSBill Taylor  * tavor_stats.c
299e39c5baSBill Taylor  *    Tavor 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/tavor/tavor.h>
439e39c5baSBill Taylor 
449e39c5baSBill Taylor static kstat_t *tavor_kstat_picN_create(tavor_state_t *state, int num_pic,
459e39c5baSBill Taylor     int num_evt, tavor_ks_mask_t *ev_array);
469e39c5baSBill Taylor static kstat_t *tavor_kstat_cntr_create(tavor_state_t *state, int num_pic,
479e39c5baSBill Taylor     int (*update)(kstat_t *, int));
489e39c5baSBill Taylor static int tavor_kstat_cntr_update(kstat_t *ksp, int rw);
499e39c5baSBill Taylor 
50e9dc6bffSRamaswamy Tummala void tavor_kstat_perfcntr64_create(tavor_state_t *state, uint_t port_num);
51e9dc6bffSRamaswamy Tummala static int tavor_kstat_perfcntr64_read(tavor_state_t *state, uint_t port,
52e9dc6bffSRamaswamy Tummala     int reset);
53e9dc6bffSRamaswamy Tummala static void tavor_kstat_perfcntr64_thread_exit(tavor_ks_info_t *ksi);
54e9dc6bffSRamaswamy Tummala static int tavor_kstat_perfcntr64_update(kstat_t *ksp, int rw);
55e9dc6bffSRamaswamy Tummala 
569e39c5baSBill Taylor /*
579e39c5baSBill Taylor  * Tavor 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 Tavor instance.
609e39c5baSBill Taylor  */
619e39c5baSBill Taylor tavor_ks_mask_t tavor_ib_perfcnt_list[TAVOR_CNTR_NUMENTRIES] = {
629e39c5baSBill Taylor 	{"port_xmit_data", TAVOR_HW_PMEG_PORTXMITDATA_OFFSET,
639e39c5baSBill Taylor 	    0, 0xFFFFFFFF, 0, 0},
649e39c5baSBill Taylor 	{"port_recv_data", TAVOR_HW_PMEG_PORTRECVDATA_OFFSET,
659e39c5baSBill Taylor 	    0, 0xFFFFFFFF, 0, 0},
669e39c5baSBill Taylor 	{"port_xmit_pkts", TAVOR_HW_PMEG_PORTXMITPKTS_OFFSET,
679e39c5baSBill Taylor 	    0, 0xFFFFFFFF, 0, 0},
689e39c5baSBill Taylor 	{"port_recv_pkts", TAVOR_HW_PMEG_PORTRECVPKTS_OFFSET,
699e39c5baSBill Taylor 	    0, 0xFFFFFFFF, 0, 0},
709e39c5baSBill Taylor 	{"port_recv_err", TAVOR_HW_PMEG_PORTRECVERR_OFFSET,
719e39c5baSBill Taylor 	    0, 0xFFFF, 0, 0},
729e39c5baSBill Taylor 	{"port_xmit_discards", TAVOR_HW_PMEG_PORTXMITDISCARD_OFFSET,
739e39c5baSBill Taylor 	    0, 0xFFFF, 0, 0},
749e39c5baSBill Taylor 	{"vl15_dropped", TAVOR_HW_PMEG_VL15DROPPED_OFFSET,
759e39c5baSBill Taylor 	    0, 0xFFFF, 0, 0},
769e39c5baSBill Taylor 	{"port_xmit_wait", TAVOR_HW_PMEG_PORTXMITWAIT_OFFSET,
779e39c5baSBill Taylor 	    0, 0xFFFFFFFF, 0, 0},
789e39c5baSBill Taylor 	{"port_recv_remote_phys_err", TAVOR_HW_PMEG_PORTRECVREMPHYSERR_OFFSET,
799e39c5baSBill Taylor 	    0, 0xFFFF, 0, 0},
809e39c5baSBill Taylor 	{"port_xmit_constraint_err", TAVOR_HW_PMEG_PORTXMITCONSTERR_OFFSET,
819e39c5baSBill Taylor 	    0, 0xFF, 0, 0},
829e39c5baSBill Taylor 	{"port_recv_constraint_err", TAVOR_HW_PMEG_PORTRECVCONSTERR_OFFSET,
839e39c5baSBill Taylor 	    0, 0xFF, 0, 0},
849e39c5baSBill Taylor 	{"symbol_err_counter", TAVOR_HW_PMEG_SYMBOLERRCNT_OFFSET,
859e39c5baSBill Taylor 	    0, 0xFFFF, 0, 0},
869e39c5baSBill Taylor 	{"link_err_recovery_cnt", TAVOR_HW_PMEG_LINKERRRECOVERCNT_OFFSET,
879e39c5baSBill Taylor 	    0, 0xFFFF, 0, 0},
889e39c5baSBill Taylor 	{"link_downed_cnt", TAVOR_HW_PMEG_LINKDOWNEDCNT_OFFSET,
899e39c5baSBill Taylor 	    16, 0xFFFF, 0, 0},
909e39c5baSBill Taylor 	{"excessive_buffer_overruns", TAVOR_HW_PMEG_EXCESSBUFOVERRUN_OFFSET,
919e39c5baSBill Taylor 	    0, 0xF, 0, 0},
929e39c5baSBill Taylor 	{"local_link_integrity_err", TAVOR_HW_PMEG_LOCALLINKINTERR_OFFSET,
939e39c5baSBill Taylor 	    8, 0xF, 0, 0},
949e39c5baSBill Taylor 	{"clear_pic", 0, 0, 0, 0}
959e39c5baSBill Taylor };
969e39c5baSBill Taylor 
97e9dc6bffSRamaswamy Tummala /*
98e9dc6bffSRamaswamy Tummala  * Return the maximum of (x) and (y)
99e9dc6bffSRamaswamy Tummala  */
100e9dc6bffSRamaswamy Tummala #define	MAX(x, y)	(((x) > (y)) ? (x) : (y))
101e9dc6bffSRamaswamy Tummala 
102e9dc6bffSRamaswamy Tummala /*
103e9dc6bffSRamaswamy Tummala  * Set (x) to the maximum of (x) and (y)
104e9dc6bffSRamaswamy Tummala  */
105e9dc6bffSRamaswamy Tummala #define	SET_TO_MAX(x, y)	\
106e9dc6bffSRamaswamy Tummala {				\
107e9dc6bffSRamaswamy Tummala 	if ((x) < (y))		\
108e9dc6bffSRamaswamy Tummala 		(x) = (y);	\
109e9dc6bffSRamaswamy Tummala }
1109e39c5baSBill Taylor 
1119e39c5baSBill Taylor /*
1129e39c5baSBill Taylor  * tavor_kstat_init()
1139e39c5baSBill Taylor  *    Context: Only called from attach() path context
1149e39c5baSBill Taylor  */
1159e39c5baSBill Taylor int
tavor_kstat_init(tavor_state_t * state)1169e39c5baSBill Taylor tavor_kstat_init(tavor_state_t *state)
1179e39c5baSBill Taylor {
1189e39c5baSBill Taylor 	tavor_ks_info_t		*ksi;
1199e39c5baSBill Taylor 	uint_t			numports;
1209e39c5baSBill Taylor 	int			i;
1219e39c5baSBill Taylor 
1229e39c5baSBill Taylor 	/* Allocate a kstat info structure */
1239e39c5baSBill Taylor 	ksi = (tavor_ks_info_t *)kmem_zalloc(sizeof (tavor_ks_info_t),
1249e39c5baSBill Taylor 	    KM_SLEEP);
1259e39c5baSBill Taylor 	if (ksi == NULL) {
1269e39c5baSBill Taylor 		return (DDI_FAILURE);
1279e39c5baSBill Taylor 	}
1289e39c5baSBill Taylor 	state->ts_ks_info = ksi;
1299e39c5baSBill Taylor 
1309e39c5baSBill Taylor 	/*
131e9dc6bffSRamaswamy Tummala 	 * Create as many "pic" and perfcntr64 kstats as we have IB ports.
132e9dc6bffSRamaswamy Tummala 	 * Enable all of the events specified in the "tavor_ib_perfcnt_list"
133e9dc6bffSRamaswamy Tummala 	 * structure.
1349e39c5baSBill Taylor 	 */
1359e39c5baSBill Taylor 	numports = state->ts_cfg_profile->cp_num_ports;
1369e39c5baSBill Taylor 	for (i = 0; i < numports; i++) {
1379e39c5baSBill Taylor 		ksi->tki_picN_ksp[i] = tavor_kstat_picN_create(state, i,
1389e39c5baSBill Taylor 		    TAVOR_CNTR_NUMENTRIES, tavor_ib_perfcnt_list);
1399e39c5baSBill Taylor 		if (ksi->tki_picN_ksp[i] == NULL) {
1409e39c5baSBill Taylor 			goto kstat_init_fail;
1419e39c5baSBill Taylor 		}
142e9dc6bffSRamaswamy Tummala 
143e9dc6bffSRamaswamy Tummala 		tavor_kstat_perfcntr64_create(state, i + 1);
144e9dc6bffSRamaswamy Tummala 		if (ksi->tki_perfcntr64[i].tki64_ksp == NULL) {
145e9dc6bffSRamaswamy Tummala 			goto kstat_init_fail;
146e9dc6bffSRamaswamy Tummala 		}
1479e39c5baSBill Taylor 	}
1489e39c5baSBill Taylor 
1499e39c5baSBill Taylor 	/* Create the "counters" kstat too */
1509e39c5baSBill Taylor 	ksi->tki_cntr_ksp = tavor_kstat_cntr_create(state, numports,
1519e39c5baSBill Taylor 	    tavor_kstat_cntr_update);
1529e39c5baSBill Taylor 	if (ksi->tki_cntr_ksp == NULL) {
1539e39c5baSBill Taylor 		goto kstat_init_fail;
1549e39c5baSBill Taylor 	}
1559e39c5baSBill Taylor 
1569e39c5baSBill Taylor 	/* Initialize the control register and initial counter values */
1579e39c5baSBill Taylor 	ksi->tki_pcr  = 0;
1589e39c5baSBill Taylor 	ksi->tki_pic0 = 0;
1599e39c5baSBill Taylor 	ksi->tki_pic1 = 0;
1609e39c5baSBill Taylor 
1619e39c5baSBill Taylor 	/*
1629e39c5baSBill Taylor 	 * Initialize the Tavor tki_ib_perfcnt[] array values using the
1639e39c5baSBill Taylor 	 * default values in tavor_ib_perfcnt_list[]
1649e39c5baSBill Taylor 	 */
1659e39c5baSBill Taylor 	for (i = 0; i < TAVOR_CNTR_NUMENTRIES; i++) {
1669e39c5baSBill Taylor 		ksi->tki_ib_perfcnt[i] = tavor_ib_perfcnt_list[i];
1679e39c5baSBill Taylor 	}
1689e39c5baSBill Taylor 
169e9dc6bffSRamaswamy Tummala 	mutex_init(&ksi->tki_perfcntr64_lock, NULL, MUTEX_DRIVER, NULL);
170e9dc6bffSRamaswamy Tummala 	cv_init(&ksi->tki_perfcntr64_cv, NULL, CV_DRIVER, NULL);
171e9dc6bffSRamaswamy Tummala 
1729e39c5baSBill Taylor 	return (DDI_SUCCESS);
1739e39c5baSBill Taylor 
1749e39c5baSBill Taylor 
1759e39c5baSBill Taylor kstat_init_fail:
1769e39c5baSBill Taylor 
1779e39c5baSBill Taylor 	/* Delete all the previously created kstats */
1789e39c5baSBill Taylor 	if (ksi->tki_cntr_ksp != NULL) {
1799e39c5baSBill Taylor 		kstat_delete(ksi->tki_cntr_ksp);
1809e39c5baSBill Taylor 	}
1819e39c5baSBill Taylor 	for (i = 0; i < numports; i++) {
1829e39c5baSBill Taylor 		if (ksi->tki_picN_ksp[i] != NULL) {
1839e39c5baSBill Taylor 			kstat_delete(ksi->tki_picN_ksp[i]);
1849e39c5baSBill Taylor 		}
185e9dc6bffSRamaswamy Tummala 		if (ksi->tki_perfcntr64[i].tki64_ksp != NULL) {
186e9dc6bffSRamaswamy Tummala 			kstat_delete(ksi->tki_perfcntr64[i].tki64_ksp);
187e9dc6bffSRamaswamy Tummala 		}
1889e39c5baSBill Taylor 	}
1899e39c5baSBill Taylor 
1909e39c5baSBill Taylor 	/* Free the kstat info structure */
1919e39c5baSBill Taylor 	kmem_free(ksi, sizeof (tavor_ks_info_t));
1929e39c5baSBill Taylor 
1939e39c5baSBill Taylor 	return (DDI_FAILURE);
1949e39c5baSBill Taylor }
1959e39c5baSBill Taylor 
1969e39c5baSBill Taylor 
1979e39c5baSBill Taylor /*
1989e39c5baSBill Taylor  * tavor_kstat_init()
1999e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
2009e39c5baSBill Taylor  */
2019e39c5baSBill Taylor void
tavor_kstat_fini(tavor_state_t * state)2029e39c5baSBill Taylor tavor_kstat_fini(tavor_state_t *state)
2039e39c5baSBill Taylor {
2049e39c5baSBill Taylor 	tavor_ks_info_t		*ksi;
2059e39c5baSBill Taylor 	uint_t			numports;
2069e39c5baSBill Taylor 	int			i;
2079e39c5baSBill Taylor 
2089e39c5baSBill Taylor 	/* Get pointer to kstat info */
2099e39c5baSBill Taylor 	ksi = state->ts_ks_info;
2109e39c5baSBill Taylor 
211e9dc6bffSRamaswamy Tummala 	/*
212e9dc6bffSRamaswamy Tummala 	 * Signal the perfcntr64_update_thread to exit and wait until the
213e9dc6bffSRamaswamy Tummala 	 * thread exits.
214e9dc6bffSRamaswamy Tummala 	 */
215e9dc6bffSRamaswamy Tummala 	mutex_enter(&ksi->tki_perfcntr64_lock);
216e9dc6bffSRamaswamy Tummala 	tavor_kstat_perfcntr64_thread_exit(ksi);
217e9dc6bffSRamaswamy Tummala 	mutex_exit(&ksi->tki_perfcntr64_lock);
218e9dc6bffSRamaswamy Tummala 
219e9dc6bffSRamaswamy Tummala 	/* Delete all the "pic" and perfcntr64 kstats (one per port) */
2209e39c5baSBill Taylor 	numports = state->ts_cfg_profile->cp_num_ports;
2219e39c5baSBill Taylor 	for (i = 0; i < numports; i++) {
2229e39c5baSBill Taylor 		if (ksi->tki_picN_ksp[i] != NULL) {
2239e39c5baSBill Taylor 			kstat_delete(ksi->tki_picN_ksp[i]);
2249e39c5baSBill Taylor 		}
225e9dc6bffSRamaswamy Tummala 		if (ksi->tki_perfcntr64[i].tki64_ksp != NULL) {
226e9dc6bffSRamaswamy Tummala 			kstat_delete(ksi->tki_perfcntr64[i].tki64_ksp);
227e9dc6bffSRamaswamy Tummala 		}
2289e39c5baSBill Taylor 	}
2299e39c5baSBill Taylor 
2309e39c5baSBill Taylor 	/* Delete the "counter" kstats (one per port) */
2319e39c5baSBill Taylor 	kstat_delete(ksi->tki_cntr_ksp);
2329e39c5baSBill Taylor 
233e9dc6bffSRamaswamy Tummala 	cv_destroy(&ksi->tki_perfcntr64_cv);
234e9dc6bffSRamaswamy Tummala 	mutex_destroy(&ksi->tki_perfcntr64_lock);
235e9dc6bffSRamaswamy Tummala 
2369e39c5baSBill Taylor 	/* Free the kstat info structure */
2379e39c5baSBill Taylor 	kmem_free(ksi, sizeof (tavor_ks_info_t));
2389e39c5baSBill Taylor }
2399e39c5baSBill Taylor 
2409e39c5baSBill Taylor 
2419e39c5baSBill Taylor /*
2429e39c5baSBill Taylor  * tavor_kstat_picN_create()
2439e39c5baSBill Taylor  *    Context: Only called from attach() path context
2449e39c5baSBill Taylor  */
2459e39c5baSBill Taylor static kstat_t *
tavor_kstat_picN_create(tavor_state_t * state,int num_pic,int num_evt,tavor_ks_mask_t * ev_array)2469e39c5baSBill Taylor tavor_kstat_picN_create(tavor_state_t *state, int num_pic, int num_evt,
2479e39c5baSBill Taylor     tavor_ks_mask_t *ev_array)
2489e39c5baSBill Taylor {
2499e39c5baSBill Taylor 	kstat_t			*picN_ksp;
2509e39c5baSBill Taylor 	struct kstat_named	*pic_named_data;
2519e39c5baSBill Taylor 	int			drv_instance, i;
2529e39c5baSBill Taylor 	char			*drv_name;
2539e39c5baSBill Taylor 	char			pic_name[16];
2549e39c5baSBill Taylor 
2559e39c5baSBill Taylor 	/*
2569e39c5baSBill Taylor 	 * Create the "picN" kstat.  In the steps, below we will attach
2579e39c5baSBill Taylor 	 * all of our named event types to it.
2589e39c5baSBill Taylor 	 */
2599e39c5baSBill Taylor 	drv_name = (char *)ddi_driver_name(state->ts_dip);
2609e39c5baSBill Taylor 	drv_instance = ddi_get_instance(state->ts_dip);
2619e39c5baSBill Taylor 	(void) sprintf(pic_name, "pic%d", num_pic);
2629e39c5baSBill Taylor 	picN_ksp = kstat_create(drv_name, drv_instance, pic_name, "bus",
2636e20df6bSToomas Soome 	    KSTAT_TYPE_NAMED, num_evt, 0);
2649e39c5baSBill Taylor 	if (picN_ksp == NULL) {
2659e39c5baSBill Taylor 		return (NULL);
2669e39c5baSBill Taylor 	}
2679e39c5baSBill Taylor 	pic_named_data = (struct kstat_named *)(picN_ksp->ks_data);
2689e39c5baSBill Taylor 
2699e39c5baSBill Taylor 	/*
2709e39c5baSBill Taylor 	 * Write event names and their associated pcr masks. The last entry
2719e39c5baSBill Taylor 	 * in the array (clear_pic) is added separately below (as its pic
2729e39c5baSBill Taylor 	 * value must be inverted).
2739e39c5baSBill Taylor 	 */
2749e39c5baSBill Taylor 	for (i = 0; i < num_evt - 1; i++) {
2759e39c5baSBill Taylor 		pic_named_data[i].value.ui64 =
2769e39c5baSBill Taylor 		    ((uint64_t)i << (num_pic * TAVOR_CNTR_SIZE));
2779e39c5baSBill Taylor 		kstat_named_init(&pic_named_data[i], ev_array[i].ks_evt_name,
2789e39c5baSBill Taylor 		    KSTAT_DATA_UINT64);
2799e39c5baSBill Taylor 	}
2809e39c5baSBill Taylor 
2819e39c5baSBill Taylor 	/* Add the "clear_pic" entry */
2829e39c5baSBill Taylor 	pic_named_data[i].value.ui64 =
2839e39c5baSBill Taylor 	    ~((uint64_t)TAVOR_CNTR_MASK << (num_pic * TAVOR_CNTR_SIZE));
2849e39c5baSBill Taylor 	kstat_named_init(&pic_named_data[i], ev_array[i].ks_evt_name,
2859e39c5baSBill Taylor 	    KSTAT_DATA_UINT64);
2869e39c5baSBill Taylor 
2879e39c5baSBill Taylor 	/* Install the kstat */
2889e39c5baSBill Taylor 	kstat_install(picN_ksp);
2899e39c5baSBill Taylor 
2909e39c5baSBill Taylor 	return (picN_ksp);
2919e39c5baSBill Taylor }
2929e39c5baSBill Taylor 
2939e39c5baSBill Taylor 
2949e39c5baSBill Taylor /*
2959e39c5baSBill Taylor  * tavor_kstat_cntr_create()
2969e39c5baSBill Taylor  *    Context: Only called from attach() path context
2979e39c5baSBill Taylor  */
2989e39c5baSBill Taylor static kstat_t *
tavor_kstat_cntr_create(tavor_state_t * state,int num_pic,int (* update)(kstat_t *,int))2999e39c5baSBill Taylor tavor_kstat_cntr_create(tavor_state_t *state, int num_pic,
3009e39c5baSBill Taylor     int (*update)(kstat_t *, int))
3019e39c5baSBill Taylor {
3029e39c5baSBill Taylor 	struct kstat		*cntr_ksp;
3039e39c5baSBill Taylor 	struct kstat_named	*cntr_named_data;
3049e39c5baSBill Taylor 	int			drv_instance, i;
3059e39c5baSBill Taylor 	char			*drv_name;
3069e39c5baSBill Taylor 	char			pic_str[16];
3079e39c5baSBill Taylor 
3089e39c5baSBill Taylor 	/*
3099e39c5baSBill Taylor 	 * Create the "counters" kstat.  In the steps, below we will attach
3109e39c5baSBill Taylor 	 * all of our "pic" to it.   Note:  The size of this kstat is
3119e39c5baSBill Taylor 	 * num_pic + 1 because it also contains the "%pcr".
3129e39c5baSBill Taylor 	 */
3139e39c5baSBill Taylor 	drv_name = (char *)ddi_driver_name(state->ts_dip);
3149e39c5baSBill Taylor 	drv_instance = ddi_get_instance(state->ts_dip);
3159e39c5baSBill Taylor 	cntr_ksp = kstat_create(drv_name, drv_instance, "counters", "bus",
3169e39c5baSBill Taylor 	    KSTAT_TYPE_NAMED, num_pic + 1, KSTAT_FLAG_WRITABLE);
3179e39c5baSBill Taylor 	if (cntr_ksp == NULL) {
3189e39c5baSBill Taylor 		return (NULL);
3199e39c5baSBill Taylor 	}
3209e39c5baSBill Taylor 	cntr_named_data = (struct kstat_named *)(cntr_ksp->ks_data);
3219e39c5baSBill Taylor 
3229e39c5baSBill Taylor 	/*
3239e39c5baSBill Taylor 	 * Initialize the named kstats (for the "pcr" and for the
3249e39c5baSBill Taylor 	 * individual "pic" kstats)
3259e39c5baSBill Taylor 	 */
3269e39c5baSBill Taylor 	kstat_named_init(&cntr_named_data[0], "pcr", KSTAT_DATA_UINT64);
3279e39c5baSBill Taylor 	for (i = 0; i < num_pic; i++) {
3289e39c5baSBill Taylor 		(void) sprintf(pic_str, "pic%d", i);
3299e39c5baSBill Taylor 		kstat_named_init(&cntr_named_data[i+1], pic_str,
3309e39c5baSBill Taylor 		    KSTAT_DATA_UINT64);
3319e39c5baSBill Taylor 	}
3329e39c5baSBill Taylor 
3339e39c5baSBill Taylor 	/*
3349e39c5baSBill Taylor 	 * Store the Tavor softstate pointer in the kstat's private field so
3359e39c5baSBill Taylor 	 * that it is available to the update function.
3369e39c5baSBill Taylor 	 */
3379e39c5baSBill Taylor 	cntr_ksp->ks_private = (void *)state;
3389e39c5baSBill Taylor 	cntr_ksp->ks_update  = update;
3399e39c5baSBill Taylor 
3409e39c5baSBill Taylor 	/* Install the kstat */
3419e39c5baSBill Taylor 	kstat_install(cntr_ksp);
3429e39c5baSBill Taylor 
3439e39c5baSBill Taylor 	return (cntr_ksp);
3449e39c5baSBill Taylor }
3459e39c5baSBill Taylor 
3469e39c5baSBill Taylor 
3479e39c5baSBill Taylor /*
3489e39c5baSBill Taylor  * tavor_kstat_cntr_update()
3499e39c5baSBill Taylor  *    Context: Called from the kstat context
3509e39c5baSBill Taylor  */
3519e39c5baSBill Taylor static int
tavor_kstat_cntr_update(kstat_t * ksp,int rw)3529e39c5baSBill Taylor tavor_kstat_cntr_update(kstat_t *ksp, int rw)
3539e39c5baSBill Taylor {
3549e39c5baSBill Taylor 	tavor_state_t		*state;
3559e39c5baSBill Taylor 	tavor_ks_mask_t		*ib_perf;
3569e39c5baSBill Taylor 	tavor_ks_info_t		*ksi;
3579e39c5baSBill Taylor 	struct kstat_named	*data;
3589e39c5baSBill Taylor 	uint64_t		offset, pcr;
3599e39c5baSBill Taylor 	uint32_t		pic0, pic1, tmp;
3609e39c5baSBill Taylor 	uint32_t		shift, mask, oldval;
3619e39c5baSBill Taylor 	uint_t			numports, indx;
3629e39c5baSBill Taylor 
3639e39c5baSBill Taylor 	/*
3649e39c5baSBill Taylor 	 * Extract the Tavor softstate pointer, kstat data, pointer to the
3659e39c5baSBill Taylor 	 * kstat info structure, and pointer to the tki_ib_perfcnt[] array
3669e39c5baSBill Taylor 	 * from the input parameters.  Note: For warlock purposes, these
3679e39c5baSBill Taylor 	 * parameters are all accessed only in this routine and are,
3689e39c5baSBill Taylor 	 * therefore, protected by the lock used by the kstat framework.
3699e39c5baSBill Taylor 	 */
3709e39c5baSBill Taylor 	state	= ksp->ks_private;
3719e39c5baSBill Taylor 	data	= (struct kstat_named *)(ksp->ks_data);
3729e39c5baSBill Taylor 	ksi	= state->ts_ks_info;
3739e39c5baSBill Taylor 	ib_perf = &ksi->tki_ib_perfcnt[0];
3749e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ksi))
3759e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
3769e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ib_perf))
3779e39c5baSBill Taylor 
3789e39c5baSBill Taylor 	/*
3799e39c5baSBill Taylor 	 * Depending on whether we are reading the "pic" counters or
3809e39c5baSBill Taylor 	 * writing the "pcr" control register, we need to handle and
3819e39c5baSBill Taylor 	 * fill in the kstat data appropriately.
3829e39c5baSBill Taylor 	 *
3839e39c5baSBill Taylor 	 * If this is a write to the "pcr", then extract the value from
3849e39c5baSBill Taylor 	 * the kstat data and store it in the kstat info structure.
3859e39c5baSBill Taylor 	 *
3869e39c5baSBill Taylor 	 * Otherwise, if this is a read of the "pic" counter(s), then
3879e39c5baSBill Taylor 	 * extract the register offset, size, and mask values from the
3889e39c5baSBill Taylor 	 * ib_perf[] array.  Then read the corresponding register and store
3899e39c5baSBill Taylor 	 * it into the kstat data.  Note:  We only read/fill in pic1 if more
3909e39c5baSBill Taylor 	 * than one port is configured.
3919e39c5baSBill Taylor 	 */
3929e39c5baSBill Taylor 	numports = state->ts_cfg_profile->cp_num_ports;
3939e39c5baSBill Taylor 	if (rw == KSTAT_WRITE) {
3949e39c5baSBill Taylor 		/* Update the stored "pcr" value */
3959e39c5baSBill Taylor 		ksi->tki_pcr = data[0].value.ui64;
3969e39c5baSBill Taylor 		return (0);
3979e39c5baSBill Taylor 	} else {
3989e39c5baSBill Taylor 		/*
3999e39c5baSBill Taylor 		 * Get the current "pcr" value and extract the lower
4009e39c5baSBill Taylor 		 * portion (corresponding to the counters for "pic0")
4019e39c5baSBill Taylor 		 */
4029e39c5baSBill Taylor 		pcr  = ksi->tki_pcr;
4039e39c5baSBill Taylor 		indx = pcr & TAVOR_CNTR_MASK;
4049e39c5baSBill Taylor 		data[0].value.ui64 = pcr;
4059e39c5baSBill Taylor 
4069e39c5baSBill Taylor 		/*
4079e39c5baSBill Taylor 		 * Fill in the "pic0" counter, corresponding to port 1.
4089e39c5baSBill Taylor 		 * This involves reading in the current value in the register
4099e39c5baSBill Taylor 		 * and calculating how many events have happened since this
4109e39c5baSBill Taylor 		 * register was last polled.  Then we save away the current
4119e39c5baSBill Taylor 		 * value for the counter and increment the "pic0" total by
4129e39c5baSBill Taylor 		 * the number of new events.
4139e39c5baSBill Taylor 		 */
4149e39c5baSBill Taylor 		offset = ib_perf[indx].ks_reg_offset;
4159e39c5baSBill Taylor 		shift  = ib_perf[indx].ks_reg_shift;
4169e39c5baSBill Taylor 		mask   = ib_perf[indx].ks_reg_mask;
4179e39c5baSBill Taylor 		oldval = ib_perf[indx].ks_old_pic0;
4189e39c5baSBill Taylor 
4199e39c5baSBill Taylor 		pic0   = ddi_get32(state->ts_reg_cmdhdl, (uint32_t *)
4209e39c5baSBill Taylor 		    (uintptr_t)((uintptr_t)state->ts_reg_cmd_baseaddr +
4219e39c5baSBill Taylor 		    offset));
4229e39c5baSBill Taylor 		tmp = ((pic0 >> shift) & mask);
4239e39c5baSBill Taylor 
4249e39c5baSBill Taylor 		ib_perf[indx].ks_old_pic0 = tmp;
4259e39c5baSBill Taylor 
4269e39c5baSBill Taylor 		tmp = tmp - oldval;
4279e39c5baSBill Taylor 		ksi->tki_pic0 += tmp;
4289e39c5baSBill Taylor 		data[1].value.ui64 = ksi->tki_pic0;
4299e39c5baSBill Taylor 
4309e39c5baSBill Taylor 		/*
4319e39c5baSBill Taylor 		 * If necessary, fill in the "pic1" counter for port 2.
4329e39c5baSBill Taylor 		 * This works the same as above except that we extract the
4339e39c5baSBill Taylor 		 * upper bits (corresponding to the counters for "pic1")
4349e39c5baSBill Taylor 		 */
4359e39c5baSBill Taylor 		if (numports == TAVOR_NUM_PORTS) {
4369e39c5baSBill Taylor 			indx   = pcr >> TAVOR_CNTR_SIZE;
4379e39c5baSBill Taylor 			offset = ib_perf[indx].ks_reg_offset;
4389e39c5baSBill Taylor 			shift  = ib_perf[indx].ks_reg_shift;
4399e39c5baSBill Taylor 			mask   = ib_perf[indx].ks_reg_mask;
4409e39c5baSBill Taylor 			oldval = ib_perf[indx].ks_old_pic1;
4419e39c5baSBill Taylor 
4429e39c5baSBill Taylor 			pic1   = ddi_get32(state->ts_reg_cmdhdl, (uint32_t *)
4439e39c5baSBill Taylor 			    (uintptr_t)((uintptr_t)state->ts_reg_cmd_baseaddr +
4449e39c5baSBill Taylor 			    offset + TAVOR_HW_PORT_SIZE));
4459e39c5baSBill Taylor 			tmp = ((pic1 >> shift) & mask);
4469e39c5baSBill Taylor 
4479e39c5baSBill Taylor 			ib_perf[indx].ks_old_pic1 = tmp;
4489e39c5baSBill Taylor 
4499e39c5baSBill Taylor 			tmp = tmp - oldval;
4509e39c5baSBill Taylor 			ksi->tki_pic1 += tmp;
4519e39c5baSBill Taylor 			data[2].value.ui64 = ksi->tki_pic1;
4529e39c5baSBill Taylor 		}
4539e39c5baSBill Taylor 
4549e39c5baSBill Taylor 		return (0);
4559e39c5baSBill Taylor 	}
4569e39c5baSBill Taylor }
457e9dc6bffSRamaswamy Tummala 
458e9dc6bffSRamaswamy Tummala /*
459e9dc6bffSRamaswamy Tummala  * 64 bit kstats for performance counters:
460e9dc6bffSRamaswamy Tummala  *
461e9dc6bffSRamaswamy Tummala  * Since the hardware as of now does not support 64 bit performance counters,
462e9dc6bffSRamaswamy Tummala  * we maintain 64 bit performance counters in software using the 32 bit
463e9dc6bffSRamaswamy Tummala  * hardware counters.
464e9dc6bffSRamaswamy Tummala  *
465e9dc6bffSRamaswamy Tummala  * We create a thread that, every one second, reads the values of 32 bit
466e9dc6bffSRamaswamy Tummala  * hardware counters and adds them to the 64 bit software counters. Immediately
467e9dc6bffSRamaswamy Tummala  * after reading, it resets the 32 bit hardware counters to zero (so that they
468e9dc6bffSRamaswamy Tummala  * start counting from zero again). At any time the current value of a counter
469e9dc6bffSRamaswamy Tummala  * is going to be the sum of the 64 bit software counter and the 32 bit
470e9dc6bffSRamaswamy Tummala  * hardware counter.
471e9dc6bffSRamaswamy Tummala  *
472e9dc6bffSRamaswamy Tummala  * Since this work need not be done if there is no consumer, by default
473e9dc6bffSRamaswamy Tummala  * we do not maintain 64 bit software counters. To enable this the consumer
474e9dc6bffSRamaswamy Tummala  * needs to write a non-zero value to the "enable" component of the of
475e9dc6bffSRamaswamy Tummala  * perf_counters kstat. Writing zero to this component will disable this work.
476e9dc6bffSRamaswamy Tummala  *
477e9dc6bffSRamaswamy Tummala  * If performance monitor is enabled in subnet manager, the SM could
478e9dc6bffSRamaswamy Tummala  * periodically reset the hardware counters by sending perf-MADs. So only
479e9dc6bffSRamaswamy Tummala  * one of either our software 64 bit counters or the SM performance monitor
480e9dc6bffSRamaswamy Tummala  * could be enabled at the same time. However, if both of them are enabled at
481e9dc6bffSRamaswamy Tummala  * the same time we still do our best by keeping track of the values of the
482e9dc6bffSRamaswamy Tummala  * last read 32 bit hardware counters. If the current read of a 32 bit hardware
483e9dc6bffSRamaswamy Tummala  * counter is less than the last read of the counter, we ignore the current
484e9dc6bffSRamaswamy Tummala  * value and go with the last read value.
485e9dc6bffSRamaswamy Tummala  */
486e9dc6bffSRamaswamy Tummala 
487e9dc6bffSRamaswamy Tummala /*
488e9dc6bffSRamaswamy Tummala  * tavor_kstat_perfcntr64_create()
489e9dc6bffSRamaswamy Tummala  *    Context: Only called from attach() path context
490e9dc6bffSRamaswamy Tummala  *
491e9dc6bffSRamaswamy Tummala  * Create "port#/perf_counters" kstat for the specified port number.
492e9dc6bffSRamaswamy Tummala  */
493e9dc6bffSRamaswamy Tummala void
tavor_kstat_perfcntr64_create(tavor_state_t * state,uint_t port_num)494e9dc6bffSRamaswamy Tummala tavor_kstat_perfcntr64_create(tavor_state_t *state, uint_t port_num)
495e9dc6bffSRamaswamy Tummala {
496e9dc6bffSRamaswamy Tummala 	tavor_ks_info_t		*ksi = state->ts_ks_info;
497e9dc6bffSRamaswamy Tummala 	struct kstat		*cntr_ksp;
498e9dc6bffSRamaswamy Tummala 	struct kstat_named	*cntr_named_data;
499e9dc6bffSRamaswamy Tummala 	int			drv_instance;
500e9dc6bffSRamaswamy Tummala 	char			*drv_name;
501e9dc6bffSRamaswamy Tummala 	char			kname[32];
502e9dc6bffSRamaswamy Tummala 
503e9dc6bffSRamaswamy Tummala 	ASSERT(port_num != 0);
504e9dc6bffSRamaswamy Tummala 
505e9dc6bffSRamaswamy Tummala 	drv_name = (char *)ddi_driver_name(state->ts_dip);
506e9dc6bffSRamaswamy Tummala 	drv_instance = ddi_get_instance(state->ts_dip);
507e9dc6bffSRamaswamy Tummala 	(void) snprintf(kname, sizeof (kname), "port%u/perf_counters",
508e9dc6bffSRamaswamy Tummala 	    port_num);
509e9dc6bffSRamaswamy Tummala 	cntr_ksp = kstat_create(drv_name, drv_instance, kname, "ib",
510e9dc6bffSRamaswamy Tummala 	    KSTAT_TYPE_NAMED, TAVOR_PERFCNTR64_NUM_COUNTERS,
511e9dc6bffSRamaswamy Tummala 	    KSTAT_FLAG_WRITABLE);
512e9dc6bffSRamaswamy Tummala 	if (cntr_ksp == NULL) {
513e9dc6bffSRamaswamy Tummala 		return;
514e9dc6bffSRamaswamy Tummala 	}
515e9dc6bffSRamaswamy Tummala 	cntr_named_data = (struct kstat_named *)(cntr_ksp->ks_data);
516e9dc6bffSRamaswamy Tummala 
517e9dc6bffSRamaswamy Tummala 	kstat_named_init(&cntr_named_data[TAVOR_PERFCNTR64_ENABLE_IDX],
518e9dc6bffSRamaswamy Tummala 	    "enable", KSTAT_DATA_UINT32);
519e9dc6bffSRamaswamy Tummala 	kstat_named_init(&cntr_named_data[TAVOR_PERFCNTR64_XMIT_DATA_IDX],
520e9dc6bffSRamaswamy Tummala 	    "xmit_data", KSTAT_DATA_UINT64);
521e9dc6bffSRamaswamy Tummala 	kstat_named_init(&cntr_named_data[TAVOR_PERFCNTR64_RECV_DATA_IDX],
522e9dc6bffSRamaswamy Tummala 	    "recv_data", KSTAT_DATA_UINT64);
523e9dc6bffSRamaswamy Tummala 	kstat_named_init(&cntr_named_data[TAVOR_PERFCNTR64_XMIT_PKTS_IDX],
524e9dc6bffSRamaswamy Tummala 	    "xmit_pkts", KSTAT_DATA_UINT64);
525e9dc6bffSRamaswamy Tummala 	kstat_named_init(&cntr_named_data[TAVOR_PERFCNTR64_RECV_PKTS_IDX],
526e9dc6bffSRamaswamy Tummala 	    "recv_pkts", KSTAT_DATA_UINT64);
527e9dc6bffSRamaswamy Tummala 
528e9dc6bffSRamaswamy Tummala 	ksi->tki_perfcntr64[port_num - 1].tki64_ksp = cntr_ksp;
529e9dc6bffSRamaswamy Tummala 	ksi->tki_perfcntr64[port_num - 1].tki64_port_num = port_num;
530e9dc6bffSRamaswamy Tummala 	ksi->tki_perfcntr64[port_num - 1].tki64_state = state;
531e9dc6bffSRamaswamy Tummala 
532e9dc6bffSRamaswamy Tummala 	cntr_ksp->ks_private = &ksi->tki_perfcntr64[port_num - 1];
533e9dc6bffSRamaswamy Tummala 	cntr_ksp->ks_update  = tavor_kstat_perfcntr64_update;
534e9dc6bffSRamaswamy Tummala 
535e9dc6bffSRamaswamy Tummala 	/* Install the kstat */
536e9dc6bffSRamaswamy Tummala 	kstat_install(cntr_ksp);
537e9dc6bffSRamaswamy Tummala }
538e9dc6bffSRamaswamy Tummala 
539e9dc6bffSRamaswamy Tummala /*
540e9dc6bffSRamaswamy Tummala  * tavor_kstat_perfcntr64_read()
541e9dc6bffSRamaswamy Tummala  *
542e9dc6bffSRamaswamy Tummala  * Read the values of 32 bit hardware counters.
543e9dc6bffSRamaswamy Tummala  *
544e9dc6bffSRamaswamy Tummala  * If reset is true, reset the 32 bit hardware counters. Add the values of the
545e9dc6bffSRamaswamy Tummala  * 32 bit hardware counters to the 64 bit software counters.
546e9dc6bffSRamaswamy Tummala  *
547e9dc6bffSRamaswamy Tummala  * If reset is false, just save the values read from the 32 bit hardware
548e9dc6bffSRamaswamy Tummala  * counters in tki64_last_read[].
549e9dc6bffSRamaswamy Tummala  *
550e9dc6bffSRamaswamy Tummala  * See the general comment on the 64 bit performance counters
551e9dc6bffSRamaswamy Tummala  * regarding the use of last read 32 bit hardware counter values.
552e9dc6bffSRamaswamy Tummala  */
553e9dc6bffSRamaswamy Tummala static int
tavor_kstat_perfcntr64_read(tavor_state_t * state,uint_t port,int reset)554e9dc6bffSRamaswamy Tummala tavor_kstat_perfcntr64_read(tavor_state_t *state, uint_t port, int reset)
555e9dc6bffSRamaswamy Tummala {
556e9dc6bffSRamaswamy Tummala 	tavor_ks_info_t	*ksi = state->ts_ks_info;
557e9dc6bffSRamaswamy Tummala 	tavor_perfcntr64_ks_info_t *ksi64 = &ksi->tki_perfcntr64[port - 1];
558e9dc6bffSRamaswamy Tummala 	int			status, i;
559e9dc6bffSRamaswamy Tummala 	uint32_t		tmp;
560e9dc6bffSRamaswamy Tummala 	tavor_hw_sm_perfcntr_t	sm_perfcntr;
561e9dc6bffSRamaswamy Tummala 
562e9dc6bffSRamaswamy Tummala 	ASSERT(MUTEX_HELD(&ksi->tki_perfcntr64_lock));
563e9dc6bffSRamaswamy Tummala 	ASSERT(port != 0);
564e9dc6bffSRamaswamy Tummala 
565e9dc6bffSRamaswamy Tummala 	/* read the 32 bit hardware counters */
566e9dc6bffSRamaswamy Tummala 	status = tavor_getperfcntr_cmd_post(state, port,
567e9dc6bffSRamaswamy Tummala 	    TAVOR_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
568e9dc6bffSRamaswamy Tummala 	if (status != TAVOR_CMD_SUCCESS) {
569e9dc6bffSRamaswamy Tummala 		return (status);
570e9dc6bffSRamaswamy Tummala 	}
571e9dc6bffSRamaswamy Tummala 
572e9dc6bffSRamaswamy Tummala 	if (reset) {
573e9dc6bffSRamaswamy Tummala 		/* reset the hardware counters */
574e9dc6bffSRamaswamy Tummala 		status = tavor_getperfcntr_cmd_post(state, port,
575e9dc6bffSRamaswamy Tummala 		    TAVOR_CMD_NOSLEEP_SPIN, NULL, 1);
576e9dc6bffSRamaswamy Tummala 		if (status != TAVOR_CMD_SUCCESS) {
577e9dc6bffSRamaswamy Tummala 			return (status);
578e9dc6bffSRamaswamy Tummala 		}
579e9dc6bffSRamaswamy Tummala 
580e9dc6bffSRamaswamy Tummala 		/*
581e9dc6bffSRamaswamy Tummala 		 * Update 64 bit software counters
582e9dc6bffSRamaswamy Tummala 		 */
583e9dc6bffSRamaswamy Tummala 		tmp = MAX(sm_perfcntr.portxmdata,
584e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_DATA_IDX]);
585e9dc6bffSRamaswamy Tummala 		ksi64->tki64_counters[TAVOR_PERFCNTR64_XMIT_DATA_IDX] += tmp;
586e9dc6bffSRamaswamy Tummala 
587e9dc6bffSRamaswamy Tummala 		tmp = MAX(sm_perfcntr.portrcdata,
588e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_DATA_IDX]);
589e9dc6bffSRamaswamy Tummala 		ksi64->tki64_counters[TAVOR_PERFCNTR64_RECV_DATA_IDX] += tmp;
590e9dc6bffSRamaswamy Tummala 
591e9dc6bffSRamaswamy Tummala 		tmp = MAX(sm_perfcntr.portxmpkts,
592e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_PKTS_IDX]);
593e9dc6bffSRamaswamy Tummala 		ksi64->tki64_counters[TAVOR_PERFCNTR64_XMIT_PKTS_IDX] += tmp;
594e9dc6bffSRamaswamy Tummala 
595e9dc6bffSRamaswamy Tummala 		tmp = MAX(sm_perfcntr.portrcpkts,
596e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_PKTS_IDX]);
597e9dc6bffSRamaswamy Tummala 		ksi64->tki64_counters[TAVOR_PERFCNTR64_RECV_PKTS_IDX] += tmp;
598e9dc6bffSRamaswamy Tummala 
599e9dc6bffSRamaswamy Tummala 		for (i = 0; i < TAVOR_PERFCNTR64_NUM_COUNTERS; i++)
600e9dc6bffSRamaswamy Tummala 			ksi64->tki64_last_read[i] = 0;
601e9dc6bffSRamaswamy Tummala 
602e9dc6bffSRamaswamy Tummala 	} else {
603e9dc6bffSRamaswamy Tummala 		/*
604e9dc6bffSRamaswamy Tummala 		 * Update ksi64->tki64_last_read[]
605e9dc6bffSRamaswamy Tummala 		 */
606e9dc6bffSRamaswamy Tummala 		SET_TO_MAX(
607e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_DATA_IDX],
608e9dc6bffSRamaswamy Tummala 		    sm_perfcntr.portxmdata);
609e9dc6bffSRamaswamy Tummala 
610e9dc6bffSRamaswamy Tummala 		SET_TO_MAX(
611e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_DATA_IDX],
612e9dc6bffSRamaswamy Tummala 		    sm_perfcntr.portrcdata);
613e9dc6bffSRamaswamy Tummala 
614e9dc6bffSRamaswamy Tummala 		SET_TO_MAX(
615e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_PKTS_IDX],
616e9dc6bffSRamaswamy Tummala 		    sm_perfcntr.portxmpkts);
617e9dc6bffSRamaswamy Tummala 
618e9dc6bffSRamaswamy Tummala 		SET_TO_MAX(
619e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_PKTS_IDX],
620e9dc6bffSRamaswamy Tummala 		    sm_perfcntr.portrcpkts);
621e9dc6bffSRamaswamy Tummala 	}
622e9dc6bffSRamaswamy Tummala 
623e9dc6bffSRamaswamy Tummala 	return (TAVOR_CMD_SUCCESS);
624e9dc6bffSRamaswamy Tummala }
625e9dc6bffSRamaswamy Tummala 
626e9dc6bffSRamaswamy Tummala /*
627e9dc6bffSRamaswamy Tummala  * tavor_kstat_perfcntr64_update_thread()
628e9dc6bffSRamaswamy Tummala  *    Context: Entry point for a kernel thread
629e9dc6bffSRamaswamy Tummala  *
630e9dc6bffSRamaswamy Tummala  * Maintain 64 bit performance counters in software using the 32 bit
631e9dc6bffSRamaswamy Tummala  * hardware counters.
632e9dc6bffSRamaswamy Tummala  */
633e9dc6bffSRamaswamy Tummala static void
tavor_kstat_perfcntr64_update_thread(void * arg)634e9dc6bffSRamaswamy Tummala tavor_kstat_perfcntr64_update_thread(void *arg)
635e9dc6bffSRamaswamy Tummala {
636e9dc6bffSRamaswamy Tummala 	tavor_state_t		*state = (tavor_state_t *)arg;
637e9dc6bffSRamaswamy Tummala 	tavor_ks_info_t		*ksi = state->ts_ks_info;
638e9dc6bffSRamaswamy Tummala 	uint_t			i;
639e9dc6bffSRamaswamy Tummala 
640e9dc6bffSRamaswamy Tummala 	mutex_enter(&ksi->tki_perfcntr64_lock);
641e9dc6bffSRamaswamy Tummala 	/*
642e9dc6bffSRamaswamy Tummala 	 * Every one second update the values 64 bit software counters
643e9dc6bffSRamaswamy Tummala 	 * for all ports. Exit if TAVOR_PERFCNTR64_THREAD_EXIT flag is set.
644e9dc6bffSRamaswamy Tummala 	 */
645e9dc6bffSRamaswamy Tummala 	while (!(ksi->tki_perfcntr64_flags & TAVOR_PERFCNTR64_THREAD_EXIT)) {
646e9dc6bffSRamaswamy Tummala 		for (i = 0; i < state->ts_cfg_profile->cp_num_ports; i++) {
647e9dc6bffSRamaswamy Tummala 			if (ksi->tki_perfcntr64[i].tki64_enabled) {
648e9dc6bffSRamaswamy Tummala 				(void) tavor_kstat_perfcntr64_read(state,
649e9dc6bffSRamaswamy Tummala 				    i + 1, 1);
650e9dc6bffSRamaswamy Tummala 			}
651e9dc6bffSRamaswamy Tummala 		}
652e9dc6bffSRamaswamy Tummala 		/* sleep for a second */
653e9dc6bffSRamaswamy Tummala 		(void) cv_timedwait(&ksi->tki_perfcntr64_cv,
654e9dc6bffSRamaswamy Tummala 		    &ksi->tki_perfcntr64_lock,
655e9dc6bffSRamaswamy Tummala 		    ddi_get_lbolt() + drv_usectohz(1000000));
656e9dc6bffSRamaswamy Tummala 	}
657e9dc6bffSRamaswamy Tummala 	ksi->tki_perfcntr64_flags = 0;
658e9dc6bffSRamaswamy Tummala 	mutex_exit(&ksi->tki_perfcntr64_lock);
659e9dc6bffSRamaswamy Tummala }
660e9dc6bffSRamaswamy Tummala 
661e9dc6bffSRamaswamy Tummala /*
662e9dc6bffSRamaswamy Tummala  * tavor_kstat_perfcntr64_thread_create()
663e9dc6bffSRamaswamy Tummala  *    Context: Called from the kstat context
664e9dc6bffSRamaswamy Tummala  *
665e9dc6bffSRamaswamy Tummala  * Create a thread that maintains 64 bit performance counters in software.
666e9dc6bffSRamaswamy Tummala  */
667e9dc6bffSRamaswamy Tummala static void
tavor_kstat_perfcntr64_thread_create(tavor_state_t * state)668e9dc6bffSRamaswamy Tummala tavor_kstat_perfcntr64_thread_create(tavor_state_t *state)
669e9dc6bffSRamaswamy Tummala {
670e9dc6bffSRamaswamy Tummala 	tavor_ks_info_t	*ksi = state->ts_ks_info;
671e9dc6bffSRamaswamy Tummala 	kthread_t		*thr;
672e9dc6bffSRamaswamy Tummala 
673e9dc6bffSRamaswamy Tummala 	ASSERT(MUTEX_HELD(&ksi->tki_perfcntr64_lock));
674e9dc6bffSRamaswamy Tummala 
675e9dc6bffSRamaswamy Tummala 	/*
676e9dc6bffSRamaswamy Tummala 	 * One thread per tavor instance. Don't create a thread if already
677e9dc6bffSRamaswamy Tummala 	 * created.
678e9dc6bffSRamaswamy Tummala 	 */
679e9dc6bffSRamaswamy Tummala 	if (!(ksi->tki_perfcntr64_flags & TAVOR_PERFCNTR64_THREAD_CREATED)) {
680e9dc6bffSRamaswamy Tummala 		thr = thread_create(NULL, 0,
681e9dc6bffSRamaswamy Tummala 		    tavor_kstat_perfcntr64_update_thread,
682e9dc6bffSRamaswamy Tummala 		    state, 0, &p0, TS_RUN, minclsyspri);
683e9dc6bffSRamaswamy Tummala 		ksi->tki_perfcntr64_thread_id = thr->t_did;
684e9dc6bffSRamaswamy Tummala 		ksi->tki_perfcntr64_flags |= TAVOR_PERFCNTR64_THREAD_CREATED;
685e9dc6bffSRamaswamy Tummala 	}
686e9dc6bffSRamaswamy Tummala }
687e9dc6bffSRamaswamy Tummala 
688e9dc6bffSRamaswamy Tummala /*
689e9dc6bffSRamaswamy Tummala  * tavor_kstat_perfcntr64_thread_exit()
690e9dc6bffSRamaswamy Tummala  *    Context: Called from attach, detach or kstat context
691e9dc6bffSRamaswamy Tummala  */
692e9dc6bffSRamaswamy Tummala static void
tavor_kstat_perfcntr64_thread_exit(tavor_ks_info_t * ksi)693e9dc6bffSRamaswamy Tummala tavor_kstat_perfcntr64_thread_exit(tavor_ks_info_t *ksi)
694e9dc6bffSRamaswamy Tummala {
695e9dc6bffSRamaswamy Tummala 	kt_did_t	tid;
696e9dc6bffSRamaswamy Tummala 
697e9dc6bffSRamaswamy Tummala 	ASSERT(MUTEX_HELD(&ksi->tki_perfcntr64_lock));
698e9dc6bffSRamaswamy Tummala 
699e9dc6bffSRamaswamy Tummala 	if (ksi->tki_perfcntr64_flags & TAVOR_PERFCNTR64_THREAD_CREATED) {
700e9dc6bffSRamaswamy Tummala 		/*
701e9dc6bffSRamaswamy Tummala 		 * Signal the thread to exit and wait until the thread exits.
702e9dc6bffSRamaswamy Tummala 		 */
703e9dc6bffSRamaswamy Tummala 		ksi->tki_perfcntr64_flags |= TAVOR_PERFCNTR64_THREAD_EXIT;
704e9dc6bffSRamaswamy Tummala 		tid = ksi->tki_perfcntr64_thread_id;
705e9dc6bffSRamaswamy Tummala 		cv_signal(&ksi->tki_perfcntr64_cv);
706e9dc6bffSRamaswamy Tummala 
707e9dc6bffSRamaswamy Tummala 		mutex_exit(&ksi->tki_perfcntr64_lock);
708e9dc6bffSRamaswamy Tummala 		thread_join(tid);
709e9dc6bffSRamaswamy Tummala 		mutex_enter(&ksi->tki_perfcntr64_lock);
710e9dc6bffSRamaswamy Tummala 	}
711e9dc6bffSRamaswamy Tummala }
712e9dc6bffSRamaswamy Tummala 
713e9dc6bffSRamaswamy Tummala /*
714e9dc6bffSRamaswamy Tummala  * tavor_kstat_perfcntr64_update()
715e9dc6bffSRamaswamy Tummala  *    Context: Called from the kstat context
716e9dc6bffSRamaswamy Tummala  *
717e9dc6bffSRamaswamy Tummala  * See the general comment on 64 bit kstats for performance counters:
718e9dc6bffSRamaswamy Tummala  */
719e9dc6bffSRamaswamy Tummala static int
tavor_kstat_perfcntr64_update(kstat_t * ksp,int rw)720e9dc6bffSRamaswamy Tummala tavor_kstat_perfcntr64_update(kstat_t *ksp, int rw)
721e9dc6bffSRamaswamy Tummala {
722e9dc6bffSRamaswamy Tummala 	tavor_state_t			*state;
723e9dc6bffSRamaswamy Tummala 	struct kstat_named		*data;
724e9dc6bffSRamaswamy Tummala 	tavor_ks_info_t		*ksi;
725e9dc6bffSRamaswamy Tummala 	tavor_perfcntr64_ks_info_t	*ksi64;
726e9dc6bffSRamaswamy Tummala 	int				i, thr_exit;
727e9dc6bffSRamaswamy Tummala 
728e9dc6bffSRamaswamy Tummala 	ksi64	= ksp->ks_private;
729e9dc6bffSRamaswamy Tummala 	state	= ksi64->tki64_state;
730e9dc6bffSRamaswamy Tummala 	ksi	= state->ts_ks_info;
731e9dc6bffSRamaswamy Tummala 	data	= (struct kstat_named *)(ksp->ks_data);
732e9dc6bffSRamaswamy Tummala 
733e9dc6bffSRamaswamy Tummala 	mutex_enter(&ksi->tki_perfcntr64_lock);
734e9dc6bffSRamaswamy Tummala 
735e9dc6bffSRamaswamy Tummala 	/*
736e9dc6bffSRamaswamy Tummala 	 * 64 bit performance counters maintained by the software is not
737e9dc6bffSRamaswamy Tummala 	 * enabled by default. Enable them upon a writing a non-zero value
738e9dc6bffSRamaswamy Tummala 	 * to "enable" kstat. Disable them upon a writing zero to the
739e9dc6bffSRamaswamy Tummala 	 * "enable" kstat.
740e9dc6bffSRamaswamy Tummala 	 */
741e9dc6bffSRamaswamy Tummala 	if (rw == KSTAT_WRITE) {
742e9dc6bffSRamaswamy Tummala 		if (data[TAVOR_PERFCNTR64_ENABLE_IDX].value.ui32) {
743e9dc6bffSRamaswamy Tummala 			if (ksi64->tki64_enabled == 0) {
744e9dc6bffSRamaswamy Tummala 				/*
745e9dc6bffSRamaswamy Tummala 				 * Reset the hardware counters to ensure that
746e9dc6bffSRamaswamy Tummala 				 * the hardware counter doesn't max out
747e9dc6bffSRamaswamy Tummala 				 * (and hence stop counting) before we get
748e9dc6bffSRamaswamy Tummala 				 * a chance to reset the counter in
749e9dc6bffSRamaswamy Tummala 				 * tavor_kstat_perfcntr64_update_thread.
750e9dc6bffSRamaswamy Tummala 				 */
751e9dc6bffSRamaswamy Tummala 				if (tavor_getperfcntr_cmd_post(state,
752e9dc6bffSRamaswamy Tummala 				    ksi64->tki64_port_num,
753e9dc6bffSRamaswamy Tummala 				    TAVOR_CMD_NOSLEEP_SPIN, NULL, 1) !=
754e9dc6bffSRamaswamy Tummala 				    TAVOR_CMD_SUCCESS) {
755e9dc6bffSRamaswamy Tummala 					mutex_exit(&ksi->tki_perfcntr64_lock);
756e9dc6bffSRamaswamy Tummala 					return (EIO);
757e9dc6bffSRamaswamy Tummala 				}
758e9dc6bffSRamaswamy Tummala 
759e9dc6bffSRamaswamy Tummala 				/* Enable 64 bit software counters */
760e9dc6bffSRamaswamy Tummala 				ksi64->tki64_enabled = 1;
761e9dc6bffSRamaswamy Tummala 				for (i = 0;
762e9dc6bffSRamaswamy Tummala 				    i < TAVOR_PERFCNTR64_NUM_COUNTERS; i++) {
763e9dc6bffSRamaswamy Tummala 					ksi64->tki64_counters[i] = 0;
764e9dc6bffSRamaswamy Tummala 					ksi64->tki64_last_read[i] = 0;
765e9dc6bffSRamaswamy Tummala 				}
766e9dc6bffSRamaswamy Tummala 				tavor_kstat_perfcntr64_thread_create(state);
767e9dc6bffSRamaswamy Tummala 			}
768e9dc6bffSRamaswamy Tummala 
769e9dc6bffSRamaswamy Tummala 		} else if (ksi64->tki64_enabled) {
770e9dc6bffSRamaswamy Tummala 			/* Disable 64 bit software counters */
771e9dc6bffSRamaswamy Tummala 			ksi64->tki64_enabled = 0;
772e9dc6bffSRamaswamy Tummala 			thr_exit = 1;
773e9dc6bffSRamaswamy Tummala 			for (i = 0; i < state->ts_cfg_profile->cp_num_ports;
774e9dc6bffSRamaswamy Tummala 			    i++) {
775e9dc6bffSRamaswamy Tummala 				if (ksi->tki_perfcntr64[i].tki64_enabled) {
776e9dc6bffSRamaswamy Tummala 					thr_exit = 0;
777e9dc6bffSRamaswamy Tummala 					break;
778e9dc6bffSRamaswamy Tummala 				}
779e9dc6bffSRamaswamy Tummala 			}
780e9dc6bffSRamaswamy Tummala 			if (thr_exit)
781e9dc6bffSRamaswamy Tummala 				tavor_kstat_perfcntr64_thread_exit(ksi);
782e9dc6bffSRamaswamy Tummala 		}
783e9dc6bffSRamaswamy Tummala 	} else if (ksi64->tki64_enabled) {
784e9dc6bffSRamaswamy Tummala 		/*
785e9dc6bffSRamaswamy Tummala 		 * Read the counters and update kstats.
786e9dc6bffSRamaswamy Tummala 		 */
787e9dc6bffSRamaswamy Tummala 		if (tavor_kstat_perfcntr64_read(state, ksi64->tki64_port_num,
788e9dc6bffSRamaswamy Tummala 		    0) != TAVOR_CMD_SUCCESS) {
789e9dc6bffSRamaswamy Tummala 			mutex_exit(&ksi->tki_perfcntr64_lock);
790e9dc6bffSRamaswamy Tummala 			return (EIO);
791e9dc6bffSRamaswamy Tummala 		}
792e9dc6bffSRamaswamy Tummala 
793e9dc6bffSRamaswamy Tummala 		data[TAVOR_PERFCNTR64_ENABLE_IDX].value.ui32 = 1;
794e9dc6bffSRamaswamy Tummala 
795e9dc6bffSRamaswamy Tummala 		data[TAVOR_PERFCNTR64_XMIT_DATA_IDX].value.ui64 =
796e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_counters[TAVOR_PERFCNTR64_XMIT_DATA_IDX] +
797e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_DATA_IDX];
798e9dc6bffSRamaswamy Tummala 
799e9dc6bffSRamaswamy Tummala 		data[TAVOR_PERFCNTR64_RECV_DATA_IDX].value.ui64 =
800e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_counters[TAVOR_PERFCNTR64_RECV_DATA_IDX] +
801e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_DATA_IDX];
802e9dc6bffSRamaswamy Tummala 
803e9dc6bffSRamaswamy Tummala 		data[TAVOR_PERFCNTR64_XMIT_PKTS_IDX].value.ui64 =
804e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_counters[TAVOR_PERFCNTR64_XMIT_PKTS_IDX] +
805e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_PKTS_IDX];
806e9dc6bffSRamaswamy Tummala 
807e9dc6bffSRamaswamy Tummala 		data[TAVOR_PERFCNTR64_RECV_PKTS_IDX].value.ui64 =
808e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_counters[TAVOR_PERFCNTR64_RECV_PKTS_IDX] +
809e9dc6bffSRamaswamy Tummala 		    ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_PKTS_IDX];
810e9dc6bffSRamaswamy Tummala 
811e9dc6bffSRamaswamy Tummala 	} else {
812e9dc6bffSRamaswamy Tummala 		/* return 0 in kstats if not enabled */
813e9dc6bffSRamaswamy Tummala 		data[TAVOR_PERFCNTR64_ENABLE_IDX].value.ui32 = 0;
814e9dc6bffSRamaswamy Tummala 		for (i = 1; i < TAVOR_PERFCNTR64_NUM_COUNTERS; i++)
815e9dc6bffSRamaswamy Tummala 			data[i].value.ui64 = 0;
816e9dc6bffSRamaswamy Tummala 	}
817e9dc6bffSRamaswamy Tummala 
818e9dc6bffSRamaswamy Tummala 	mutex_exit(&ksi->tki_perfcntr64_lock);
819e9dc6bffSRamaswamy Tummala 	return (0);
820e9dc6bffSRamaswamy Tummala }
821