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