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