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