1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * tavor_stats.c
  29  *    Tavor IB Performance Statistics routines
  30  *
  31  *    Implements all the routines necessary for setting up, querying, and
  32  *    (later) tearing down all the kstats necessary for implementing to
  33  *    the interfaces necessary to provide busstat(1M) access.
  34  */
  35 
  36 #include <sys/types.h>
  37 #include <sys/conf.h>
  38 #include <sys/ddi.h>
  39 #include <sys/sunddi.h>
  40 #include <sys/modctl.h>
  41 
  42 #include <sys/ib/adapters/tavor/tavor.h>
  43 
  44 static kstat_t *tavor_kstat_picN_create(tavor_state_t *state, int num_pic,
  45     int num_evt, tavor_ks_mask_t *ev_array);
  46 static kstat_t *tavor_kstat_cntr_create(tavor_state_t *state, int num_pic,
  47     int (*update)(kstat_t *, int));
  48 static int tavor_kstat_cntr_update(kstat_t *ksp, int rw);
  49 
  50 void tavor_kstat_perfcntr64_create(tavor_state_t *state, uint_t port_num);
  51 static int tavor_kstat_perfcntr64_read(tavor_state_t *state, uint_t port,
  52     int reset);
  53 static void tavor_kstat_perfcntr64_thread_exit(tavor_ks_info_t *ksi);
  54 static int tavor_kstat_perfcntr64_update(kstat_t *ksp, int rw);
  55 
  56 /*
  57  * Tavor IB Performance Events structure
  58  *    This structure is read-only and is used to setup the individual kstats
  59  *    and to initialize the tki_ib_perfcnt[] array for each Tavor instance.
  60  */
  61 tavor_ks_mask_t tavor_ib_perfcnt_list[TAVOR_CNTR_NUMENTRIES] = {
  62         {"port_xmit_data", TAVOR_HW_PMEG_PORTXMITDATA_OFFSET,
  63             0, 0xFFFFFFFF, 0, 0},
  64         {"port_recv_data", TAVOR_HW_PMEG_PORTRECVDATA_OFFSET,
  65             0, 0xFFFFFFFF, 0, 0},
  66         {"port_xmit_pkts", TAVOR_HW_PMEG_PORTXMITPKTS_OFFSET,
  67             0, 0xFFFFFFFF, 0, 0},
  68         {"port_recv_pkts", TAVOR_HW_PMEG_PORTRECVPKTS_OFFSET,
  69             0, 0xFFFFFFFF, 0, 0},
  70         {"port_recv_err", TAVOR_HW_PMEG_PORTRECVERR_OFFSET,
  71             0, 0xFFFF, 0, 0},
  72         {"port_xmit_discards", TAVOR_HW_PMEG_PORTXMITDISCARD_OFFSET,
  73             0, 0xFFFF, 0, 0},
  74         {"vl15_dropped", TAVOR_HW_PMEG_VL15DROPPED_OFFSET,
  75             0, 0xFFFF, 0, 0},
  76         {"port_xmit_wait", TAVOR_HW_PMEG_PORTXMITWAIT_OFFSET,
  77             0, 0xFFFFFFFF, 0, 0},
  78         {"port_recv_remote_phys_err", TAVOR_HW_PMEG_PORTRECVREMPHYSERR_OFFSET,
  79             0, 0xFFFF, 0, 0},
  80         {"port_xmit_constraint_err", TAVOR_HW_PMEG_PORTXMITCONSTERR_OFFSET,
  81             0, 0xFF, 0, 0},
  82         {"port_recv_constraint_err", TAVOR_HW_PMEG_PORTRECVCONSTERR_OFFSET,
  83             0, 0xFF, 0, 0},
  84         {"symbol_err_counter", TAVOR_HW_PMEG_SYMBOLERRCNT_OFFSET,
  85             0, 0xFFFF, 0, 0},
  86         {"link_err_recovery_cnt", TAVOR_HW_PMEG_LINKERRRECOVERCNT_OFFSET,
  87             0, 0xFFFF, 0, 0},
  88         {"link_downed_cnt", TAVOR_HW_PMEG_LINKDOWNEDCNT_OFFSET,
  89             16, 0xFFFF, 0, 0},
  90         {"excessive_buffer_overruns", TAVOR_HW_PMEG_EXCESSBUFOVERRUN_OFFSET,
  91             0, 0xF, 0, 0},
  92         {"local_link_integrity_err", TAVOR_HW_PMEG_LOCALLINKINTERR_OFFSET,
  93             8, 0xF, 0, 0},
  94         {"clear_pic", 0, 0, 0, 0}
  95 };
  96 
  97 /*
  98  * Return the maximum of (x) and (y)
  99  */
 100 #define MAX(x, y)       (((x) > (y)) ? (x) : (y))
 101 
 102 /*
 103  * Set (x) to the maximum of (x) and (y)
 104  */
 105 #define SET_TO_MAX(x, y)        \
 106 {                               \
 107         if ((x) < (y))               \
 108                 (x) = (y);      \
 109 }
 110 
 111 /*
 112  * tavor_kstat_init()
 113  *    Context: Only called from attach() path context
 114  */
 115 int
 116 tavor_kstat_init(tavor_state_t *state)
 117 {
 118         tavor_ks_info_t         *ksi;
 119         uint_t                  numports;
 120         int                     i;
 121 
 122         TAVOR_TNF_ENTER(tavor_kstat_init);
 123 
 124         /* Allocate a kstat info structure */
 125         ksi = (tavor_ks_info_t *)kmem_zalloc(sizeof (tavor_ks_info_t),
 126             KM_SLEEP);
 127         if (ksi == NULL) {
 128                 TNF_PROBE_0(tavor_kstat_init_kma_fail, TAVOR_TNF_ERROR, "");
 129                 TAVOR_TNF_EXIT(tavor_kstat_init);
 130                 return (DDI_FAILURE);
 131         }
 132         state->ts_ks_info = ksi;
 133 
 134         /*
 135          * Create as many "pic" and perfcntr64 kstats as we have IB ports.
 136          * Enable all of the events specified in the "tavor_ib_perfcnt_list"
 137          * structure.
 138          */
 139         numports = state->ts_cfg_profile->cp_num_ports;
 140         for (i = 0; i < numports; i++) {
 141                 ksi->tki_picN_ksp[i] = tavor_kstat_picN_create(state, i,
 142                     TAVOR_CNTR_NUMENTRIES, tavor_ib_perfcnt_list);
 143                 if (ksi->tki_picN_ksp[i] == NULL) {
 144                         TNF_PROBE_0(tavor_kstat_init_picN_fail,
 145                             TAVOR_TNF_ERROR, "");
 146                         goto kstat_init_fail;
 147                 }
 148 
 149                 tavor_kstat_perfcntr64_create(state, i + 1);
 150                 if (ksi->tki_perfcntr64[i].tki64_ksp == NULL) {
 151                         goto kstat_init_fail;
 152                 }
 153         }
 154 
 155         /* Create the "counters" kstat too */
 156         ksi->tki_cntr_ksp = tavor_kstat_cntr_create(state, numports,
 157             tavor_kstat_cntr_update);
 158         if (ksi->tki_cntr_ksp == NULL) {
 159                 TNF_PROBE_0(tavor_kstat_init_cntr_fail, TAVOR_TNF_ERROR, "");
 160                 goto kstat_init_fail;
 161         }
 162 
 163         /* Initialize the control register and initial counter values */
 164         ksi->tki_pcr  = 0;
 165         ksi->tki_pic0 = 0;
 166         ksi->tki_pic1 = 0;
 167 
 168         /*
 169          * Initialize the Tavor tki_ib_perfcnt[] array values using the
 170          * default values in tavor_ib_perfcnt_list[]
 171          */
 172         for (i = 0; i < TAVOR_CNTR_NUMENTRIES; i++) {
 173                 ksi->tki_ib_perfcnt[i] = tavor_ib_perfcnt_list[i];
 174         }
 175 
 176         mutex_init(&ksi->tki_perfcntr64_lock, NULL, MUTEX_DRIVER, NULL);
 177         cv_init(&ksi->tki_perfcntr64_cv, NULL, CV_DRIVER, NULL);
 178 
 179         TAVOR_TNF_EXIT(tavor_kstat_init);
 180         return (DDI_SUCCESS);
 181 
 182 
 183 kstat_init_fail:
 184 
 185         /* Delete all the previously created kstats */
 186         if (ksi->tki_cntr_ksp != NULL) {
 187                 kstat_delete(ksi->tki_cntr_ksp);
 188         }
 189         for (i = 0; i < numports; i++) {
 190                 if (ksi->tki_picN_ksp[i] != NULL) {
 191                         kstat_delete(ksi->tki_picN_ksp[i]);
 192                 }
 193                 if (ksi->tki_perfcntr64[i].tki64_ksp != NULL) {
 194                         kstat_delete(ksi->tki_perfcntr64[i].tki64_ksp);
 195                 }
 196         }
 197 
 198         /* Free the kstat info structure */
 199         kmem_free(ksi, sizeof (tavor_ks_info_t));
 200 
 201         TAVOR_TNF_EXIT(tavor_kstat_init);
 202         return (DDI_FAILURE);
 203 }
 204 
 205 
 206 /*
 207  * tavor_kstat_init()
 208  *    Context: Only called from attach() and/or detach() path contexts
 209  */
 210 void
 211 tavor_kstat_fini(tavor_state_t *state)
 212 {
 213         tavor_ks_info_t         *ksi;
 214         uint_t                  numports;
 215         int                     i;
 216 
 217         TAVOR_TNF_ENTER(tavor_kstat_fini);
 218 
 219         /* Get pointer to kstat info */
 220         ksi = state->ts_ks_info;
 221 
 222         /*
 223          * Signal the perfcntr64_update_thread to exit and wait until the
 224          * thread exits.
 225          */
 226         mutex_enter(&ksi->tki_perfcntr64_lock);
 227         tavor_kstat_perfcntr64_thread_exit(ksi);
 228         mutex_exit(&ksi->tki_perfcntr64_lock);
 229 
 230         /* Delete all the "pic" and perfcntr64 kstats (one per port) */
 231         numports = state->ts_cfg_profile->cp_num_ports;
 232         for (i = 0; i < numports; i++) {
 233                 if (ksi->tki_picN_ksp[i] != NULL) {
 234                         kstat_delete(ksi->tki_picN_ksp[i]);
 235                 }
 236                 if (ksi->tki_perfcntr64[i].tki64_ksp != NULL) {
 237                         kstat_delete(ksi->tki_perfcntr64[i].tki64_ksp);
 238                 }
 239         }
 240 
 241         /* Delete the "counter" kstats (one per port) */
 242         kstat_delete(ksi->tki_cntr_ksp);
 243 
 244         cv_destroy(&ksi->tki_perfcntr64_cv);
 245         mutex_destroy(&ksi->tki_perfcntr64_lock);
 246 
 247         /* Free the kstat info structure */
 248         kmem_free(ksi, sizeof (tavor_ks_info_t));
 249 
 250         TAVOR_TNF_EXIT(tavor_kstat_fini);
 251 }
 252 
 253 
 254 /*
 255  * tavor_kstat_picN_create()
 256  *    Context: Only called from attach() path context
 257  */
 258 static kstat_t *
 259 tavor_kstat_picN_create(tavor_state_t *state, int num_pic, int num_evt,
 260     tavor_ks_mask_t *ev_array)
 261 {
 262         kstat_t                 *picN_ksp;
 263         struct kstat_named      *pic_named_data;
 264         int                     drv_instance, i;
 265         char                    *drv_name;
 266         char                    pic_name[16];
 267 
 268         TAVOR_TNF_ENTER(tavor_kstat_picN_create);
 269 
 270         /*
 271          * Create the "picN" kstat.  In the steps, below we will attach
 272          * all of our named event types to it.
 273          */
 274         drv_name = (char *)ddi_driver_name(state->ts_dip);
 275         drv_instance = ddi_get_instance(state->ts_dip);
 276         (void) sprintf(pic_name, "pic%d", num_pic);
 277         picN_ksp = kstat_create(drv_name, drv_instance, pic_name, "bus",
 278             KSTAT_TYPE_NAMED, num_evt, NULL);
 279         if (picN_ksp == NULL) {
 280                 TNF_PROBE_0(tavor_kstat_picN_create_kstat_fail,
 281                     TAVOR_TNF_ERROR, "");
 282                 TAVOR_TNF_EXIT(tavor_kstat_picN_create);
 283                 return (NULL);
 284         }
 285         pic_named_data = (struct kstat_named *)(picN_ksp->ks_data);
 286 
 287         /*
 288          * Write event names and their associated pcr masks. The last entry
 289          * in the array (clear_pic) is added separately below (as its pic
 290          * value must be inverted).
 291          */
 292         for (i = 0; i < num_evt - 1; i++) {
 293                 pic_named_data[i].value.ui64 =
 294                     ((uint64_t)i << (num_pic * TAVOR_CNTR_SIZE));
 295                 kstat_named_init(&pic_named_data[i], ev_array[i].ks_evt_name,
 296                     KSTAT_DATA_UINT64);
 297         }
 298 
 299         /* Add the "clear_pic" entry */
 300         pic_named_data[i].value.ui64 =
 301             ~((uint64_t)TAVOR_CNTR_MASK << (num_pic * TAVOR_CNTR_SIZE));
 302         kstat_named_init(&pic_named_data[i], ev_array[i].ks_evt_name,
 303             KSTAT_DATA_UINT64);
 304 
 305         /* Install the kstat */
 306         kstat_install(picN_ksp);
 307 
 308         TAVOR_TNF_EXIT(tavor_kstat_picN_create);
 309         return (picN_ksp);
 310 }
 311 
 312 
 313 /*
 314  * tavor_kstat_cntr_create()
 315  *    Context: Only called from attach() path context
 316  */
 317 static kstat_t *
 318 tavor_kstat_cntr_create(tavor_state_t *state, int num_pic,
 319     int (*update)(kstat_t *, int))
 320 {
 321         struct kstat            *cntr_ksp;
 322         struct kstat_named      *cntr_named_data;
 323         int                     drv_instance, i;
 324         char                    *drv_name;
 325         char                    pic_str[16];
 326 
 327         TAVOR_TNF_ENTER(tavor_kstat_cntr_create);
 328 
 329         /*
 330          * Create the "counters" kstat.  In the steps, below we will attach
 331          * all of our "pic" to it.   Note:  The size of this kstat is
 332          * num_pic + 1 because it also contains the "%pcr".
 333          */
 334         drv_name = (char *)ddi_driver_name(state->ts_dip);
 335         drv_instance = ddi_get_instance(state->ts_dip);
 336         cntr_ksp = kstat_create(drv_name, drv_instance, "counters", "bus",
 337             KSTAT_TYPE_NAMED, num_pic + 1, KSTAT_FLAG_WRITABLE);
 338         if (cntr_ksp == NULL) {
 339                 TNF_PROBE_0(tavor_kstat_picN_create_kstat_fail,
 340                     TAVOR_TNF_ERROR, "");
 341                 TAVOR_TNF_EXIT(tavor_kstat_cntr_create);
 342                 return (NULL);
 343         }
 344         cntr_named_data = (struct kstat_named *)(cntr_ksp->ks_data);
 345 
 346         /*
 347          * Initialize the named kstats (for the "pcr" and for the
 348          * individual "pic" kstats)
 349          */
 350         kstat_named_init(&cntr_named_data[0], "pcr", KSTAT_DATA_UINT64);
 351         for (i = 0; i < num_pic; i++) {
 352                 (void) sprintf(pic_str, "pic%d", i);
 353                 kstat_named_init(&cntr_named_data[i+1], pic_str,
 354                     KSTAT_DATA_UINT64);
 355         }
 356 
 357         /*
 358          * Store the Tavor softstate pointer in the kstat's private field so
 359          * that it is available to the update function.
 360          */
 361         cntr_ksp->ks_private = (void *)state;
 362         cntr_ksp->ks_update  = update;
 363 
 364         /* Install the kstat */
 365         kstat_install(cntr_ksp);
 366 
 367         TAVOR_TNF_ENTER(tavor_kstat_cntr_create);
 368         return (cntr_ksp);
 369 }
 370 
 371 
 372 /*
 373  * tavor_kstat_cntr_update()
 374  *    Context: Called from the kstat context
 375  */
 376 static int
 377 tavor_kstat_cntr_update(kstat_t *ksp, int rw)
 378 {
 379         tavor_state_t           *state;
 380         tavor_ks_mask_t         *ib_perf;
 381         tavor_ks_info_t         *ksi;
 382         struct kstat_named      *data;
 383         uint64_t                offset, pcr;
 384         uint32_t                pic0, pic1, tmp;
 385         uint32_t                shift, mask, oldval;
 386         uint_t                  numports, indx;
 387 
 388         TAVOR_TNF_ENTER(tavor_kstat_cntr_update);
 389 
 390         /*
 391          * Extract the Tavor softstate pointer, kstat data, pointer to the
 392          * kstat info structure, and pointer to the tki_ib_perfcnt[] array
 393          * from the input parameters.
 394          */
 395         state   = ksp->ks_private;
 396         data    = (struct kstat_named *)(ksp->ks_data);
 397         ksi     = state->ts_ks_info;
 398         ib_perf = &ksi->tki_ib_perfcnt[0];
 399 
 400         /*
 401          * Depending on whether we are reading the "pic" counters or
 402          * writing the "pcr" control register, we need to handle and
 403          * fill in the kstat data appropriately.
 404          *
 405          * If this is a write to the "pcr", then extract the value from
 406          * the kstat data and store it in the kstat info structure.
 407          *
 408          * Otherwise, if this is a read of the "pic" counter(s), then
 409          * extract the register offset, size, and mask values from the
 410          * ib_perf[] array.  Then read the corresponding register and store
 411          * it into the kstat data.  Note:  We only read/fill in pic1 if more
 412          * than one port is configured.
 413          */
 414         numports = state->ts_cfg_profile->cp_num_ports;
 415         if (rw == KSTAT_WRITE) {
 416                 /* Update the stored "pcr" value */
 417                 ksi->tki_pcr = data[0].value.ui64;
 418                 TAVOR_TNF_EXIT(tavor_kstat_cntr_update);
 419                 return (0);
 420         } else {
 421                 /*
 422                  * Get the current "pcr" value and extract the lower
 423                  * portion (corresponding to the counters for "pic0")
 424                  */
 425                 pcr  = ksi->tki_pcr;
 426                 indx = pcr & TAVOR_CNTR_MASK;
 427                 data[0].value.ui64 = pcr;
 428 
 429                 /*
 430                  * Fill in the "pic0" counter, corresponding to port 1.
 431                  * This involves reading in the current value in the register
 432                  * and calculating how many events have happened since this
 433                  * register was last polled.  Then we save away the current
 434                  * value for the counter and increment the "pic0" total by
 435                  * the number of new events.
 436                  */
 437                 offset = ib_perf[indx].ks_reg_offset;
 438                 shift  = ib_perf[indx].ks_reg_shift;
 439                 mask   = ib_perf[indx].ks_reg_mask;
 440                 oldval = ib_perf[indx].ks_old_pic0;
 441 
 442                 pic0   = ddi_get32(state->ts_reg_cmdhdl, (uint32_t *)
 443                     (uintptr_t)((uintptr_t)state->ts_reg_cmd_baseaddr +
 444                     offset));
 445                 tmp = ((pic0 >> shift) & mask);
 446 
 447                 ib_perf[indx].ks_old_pic0 = tmp;
 448 
 449                 tmp = tmp - oldval;
 450                 ksi->tki_pic0 += tmp;
 451                 data[1].value.ui64 = ksi->tki_pic0;
 452 
 453                 /*
 454                  * If necessary, fill in the "pic1" counter for port 2.
 455                  * This works the same as above except that we extract the
 456                  * upper bits (corresponding to the counters for "pic1")
 457                  */
 458                 if (numports == TAVOR_NUM_PORTS) {
 459                         indx   = pcr >> TAVOR_CNTR_SIZE;
 460                         offset = ib_perf[indx].ks_reg_offset;
 461                         shift  = ib_perf[indx].ks_reg_shift;
 462                         mask   = ib_perf[indx].ks_reg_mask;
 463                         oldval = ib_perf[indx].ks_old_pic1;
 464 
 465                         pic1   = ddi_get32(state->ts_reg_cmdhdl, (uint32_t *)
 466                             (uintptr_t)((uintptr_t)state->ts_reg_cmd_baseaddr +
 467                             offset + TAVOR_HW_PORT_SIZE));
 468                         tmp = ((pic1 >> shift) & mask);
 469 
 470                         ib_perf[indx].ks_old_pic1 = tmp;
 471 
 472                         tmp = tmp - oldval;
 473                         ksi->tki_pic1 += tmp;
 474                         data[2].value.ui64 = ksi->tki_pic1;
 475                 }
 476 
 477                 TAVOR_TNF_EXIT(tavor_kstat_cntr_update);
 478                 return (0);
 479         }
 480 }
 481 
 482 /*
 483  * 64 bit kstats for performance counters:
 484  *
 485  * Since the hardware as of now does not support 64 bit performance counters,
 486  * we maintain 64 bit performance counters in software using the 32 bit
 487  * hardware counters.
 488  *
 489  * We create a thread that, every one second, reads the values of 32 bit
 490  * hardware counters and adds them to the 64 bit software counters. Immediately
 491  * after reading, it resets the 32 bit hardware counters to zero (so that they
 492  * start counting from zero again). At any time the current value of a counter
 493  * is going to be the sum of the 64 bit software counter and the 32 bit
 494  * hardware counter.
 495  *
 496  * Since this work need not be done if there is no consumer, by default
 497  * we do not maintain 64 bit software counters. To enable this the consumer
 498  * needs to write a non-zero value to the "enable" component of the of
 499  * perf_counters kstat. Writing zero to this component will disable this work.
 500  *
 501  * If performance monitor is enabled in subnet manager, the SM could
 502  * periodically reset the hardware counters by sending perf-MADs. So only
 503  * one of either our software 64 bit counters or the SM performance monitor
 504  * could be enabled at the same time. However, if both of them are enabled at
 505  * the same time we still do our best by keeping track of the values of the
 506  * last read 32 bit hardware counters. If the current read of a 32 bit hardware
 507  * counter is less than the last read of the counter, we ignore the current
 508  * value and go with the last read value.
 509  */
 510 
 511 /*
 512  * tavor_kstat_perfcntr64_create()
 513  *    Context: Only called from attach() path context
 514  *
 515  * Create "port#/perf_counters" kstat for the specified port number.
 516  */
 517 void
 518 tavor_kstat_perfcntr64_create(tavor_state_t *state, uint_t port_num)
 519 {
 520         tavor_ks_info_t         *ksi = state->ts_ks_info;
 521         struct kstat            *cntr_ksp;
 522         struct kstat_named      *cntr_named_data;
 523         int                     drv_instance;
 524         char                    *drv_name;
 525         char                    kname[32];
 526 
 527         ASSERT(port_num != 0);
 528 
 529         drv_name = (char *)ddi_driver_name(state->ts_dip);
 530         drv_instance = ddi_get_instance(state->ts_dip);
 531         (void) snprintf(kname, sizeof (kname), "port%u/perf_counters",
 532             port_num);
 533         cntr_ksp = kstat_create(drv_name, drv_instance, kname, "ib",
 534             KSTAT_TYPE_NAMED, TAVOR_PERFCNTR64_NUM_COUNTERS,
 535             KSTAT_FLAG_WRITABLE);
 536         if (cntr_ksp == NULL) {
 537                 return;
 538         }
 539         cntr_named_data = (struct kstat_named *)(cntr_ksp->ks_data);
 540 
 541         kstat_named_init(&cntr_named_data[TAVOR_PERFCNTR64_ENABLE_IDX],
 542             "enable", KSTAT_DATA_UINT32);
 543         kstat_named_init(&cntr_named_data[TAVOR_PERFCNTR64_XMIT_DATA_IDX],
 544             "xmit_data", KSTAT_DATA_UINT64);
 545         kstat_named_init(&cntr_named_data[TAVOR_PERFCNTR64_RECV_DATA_IDX],
 546             "recv_data", KSTAT_DATA_UINT64);
 547         kstat_named_init(&cntr_named_data[TAVOR_PERFCNTR64_XMIT_PKTS_IDX],
 548             "xmit_pkts", KSTAT_DATA_UINT64);
 549         kstat_named_init(&cntr_named_data[TAVOR_PERFCNTR64_RECV_PKTS_IDX],
 550             "recv_pkts", KSTAT_DATA_UINT64);
 551 
 552         ksi->tki_perfcntr64[port_num - 1].tki64_ksp = cntr_ksp;
 553         ksi->tki_perfcntr64[port_num - 1].tki64_port_num = port_num;
 554         ksi->tki_perfcntr64[port_num - 1].tki64_state = state;
 555 
 556         cntr_ksp->ks_private = &ksi->tki_perfcntr64[port_num - 1];
 557         cntr_ksp->ks_update  = tavor_kstat_perfcntr64_update;
 558 
 559         /* Install the kstat */
 560         kstat_install(cntr_ksp);
 561 }
 562 
 563 /*
 564  * tavor_kstat_perfcntr64_read()
 565  *
 566  * Read the values of 32 bit hardware counters.
 567  *
 568  * If reset is true, reset the 32 bit hardware counters. Add the values of the
 569  * 32 bit hardware counters to the 64 bit software counters.
 570  *
 571  * If reset is false, just save the values read from the 32 bit hardware
 572  * counters in tki64_last_read[].
 573  *
 574  * See the general comment on the 64 bit performance counters
 575  * regarding the use of last read 32 bit hardware counter values.
 576  */
 577 static int
 578 tavor_kstat_perfcntr64_read(tavor_state_t *state, uint_t port, int reset)
 579 {
 580         tavor_ks_info_t *ksi = state->ts_ks_info;
 581         tavor_perfcntr64_ks_info_t *ksi64 = &ksi->tki_perfcntr64[port - 1];
 582         int                     status, i;
 583         uint32_t                tmp;
 584         tavor_hw_sm_perfcntr_t  sm_perfcntr;
 585 
 586         ASSERT(MUTEX_HELD(&ksi->tki_perfcntr64_lock));
 587         ASSERT(port != 0);
 588 
 589         /* read the 32 bit hardware counters */
 590         status = tavor_getperfcntr_cmd_post(state, port,
 591             TAVOR_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
 592         if (status != TAVOR_CMD_SUCCESS) {
 593                 return (status);
 594         }
 595 
 596         if (reset) {
 597                 /* reset the hardware counters */
 598                 status = tavor_getperfcntr_cmd_post(state, port,
 599                     TAVOR_CMD_NOSLEEP_SPIN, NULL, 1);
 600                 if (status != TAVOR_CMD_SUCCESS) {
 601                         return (status);
 602                 }
 603 
 604                 /*
 605                  * Update 64 bit software counters
 606                  */
 607                 tmp = MAX(sm_perfcntr.portxmdata,
 608                     ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_DATA_IDX]);
 609                 ksi64->tki64_counters[TAVOR_PERFCNTR64_XMIT_DATA_IDX] += tmp;
 610 
 611                 tmp = MAX(sm_perfcntr.portrcdata,
 612                     ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_DATA_IDX]);
 613                 ksi64->tki64_counters[TAVOR_PERFCNTR64_RECV_DATA_IDX] += tmp;
 614 
 615                 tmp = MAX(sm_perfcntr.portxmpkts,
 616                     ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_PKTS_IDX]);
 617                 ksi64->tki64_counters[TAVOR_PERFCNTR64_XMIT_PKTS_IDX] += tmp;
 618 
 619                 tmp = MAX(sm_perfcntr.portrcpkts,
 620                     ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_PKTS_IDX]);
 621                 ksi64->tki64_counters[TAVOR_PERFCNTR64_RECV_PKTS_IDX] += tmp;
 622 
 623                 for (i = 0; i < TAVOR_PERFCNTR64_NUM_COUNTERS; i++)
 624                         ksi64->tki64_last_read[i] = 0;
 625 
 626         } else {
 627                 /*
 628                  * Update ksi64->tki64_last_read[]
 629                  */
 630                 SET_TO_MAX(
 631                     ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_DATA_IDX],
 632                     sm_perfcntr.portxmdata);
 633 
 634                 SET_TO_MAX(
 635                     ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_DATA_IDX],
 636                     sm_perfcntr.portrcdata);
 637 
 638                 SET_TO_MAX(
 639                     ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_PKTS_IDX],
 640                     sm_perfcntr.portxmpkts);
 641 
 642                 SET_TO_MAX(
 643                     ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_PKTS_IDX],
 644                     sm_perfcntr.portrcpkts);
 645         }
 646 
 647         return (TAVOR_CMD_SUCCESS);
 648 }
 649 
 650 /*
 651  * tavor_kstat_perfcntr64_update_thread()
 652  *    Context: Entry point for a kernel thread
 653  *
 654  * Maintain 64 bit performance counters in software using the 32 bit
 655  * hardware counters.
 656  */
 657 static void
 658 tavor_kstat_perfcntr64_update_thread(void *arg)
 659 {
 660         tavor_state_t           *state = (tavor_state_t *)arg;
 661         tavor_ks_info_t         *ksi = state->ts_ks_info;
 662         uint_t                  i;
 663 
 664         mutex_enter(&ksi->tki_perfcntr64_lock);
 665         /*
 666          * Every one second update the values 64 bit software counters
 667          * for all ports. Exit if TAVOR_PERFCNTR64_THREAD_EXIT flag is set.
 668          */
 669         while (!(ksi->tki_perfcntr64_flags & TAVOR_PERFCNTR64_THREAD_EXIT)) {
 670                 for (i = 0; i < state->ts_cfg_profile->cp_num_ports; i++) {
 671                         if (ksi->tki_perfcntr64[i].tki64_enabled) {
 672                                 (void) tavor_kstat_perfcntr64_read(state,
 673                                     i + 1, 1);
 674                         }
 675                 }
 676                 /* sleep for a second */
 677                 (void) cv_timedwait(&ksi->tki_perfcntr64_cv,
 678                     &ksi->tki_perfcntr64_lock,
 679                     ddi_get_lbolt() + drv_usectohz(1000000));
 680         }
 681         ksi->tki_perfcntr64_flags = 0;
 682         mutex_exit(&ksi->tki_perfcntr64_lock);
 683 }
 684 
 685 /*
 686  * tavor_kstat_perfcntr64_thread_create()
 687  *    Context: Called from the kstat context
 688  *
 689  * Create a thread that maintains 64 bit performance counters in software.
 690  */
 691 static void
 692 tavor_kstat_perfcntr64_thread_create(tavor_state_t *state)
 693 {
 694         tavor_ks_info_t *ksi = state->ts_ks_info;
 695         kthread_t               *thr;
 696 
 697         ASSERT(MUTEX_HELD(&ksi->tki_perfcntr64_lock));
 698 
 699         /*
 700          * One thread per tavor instance. Don't create a thread if already
 701          * created.
 702          */
 703         if (!(ksi->tki_perfcntr64_flags & TAVOR_PERFCNTR64_THREAD_CREATED)) {
 704                 thr = thread_create(NULL, 0,
 705                     tavor_kstat_perfcntr64_update_thread,
 706                     state, 0, &p0, TS_RUN, minclsyspri);
 707                 ksi->tki_perfcntr64_thread_id = thr->t_did;
 708                 ksi->tki_perfcntr64_flags |= TAVOR_PERFCNTR64_THREAD_CREATED;
 709         }
 710 }
 711 
 712 /*
 713  * tavor_kstat_perfcntr64_thread_exit()
 714  *    Context: Called from attach, detach or kstat context
 715  */
 716 static void
 717 tavor_kstat_perfcntr64_thread_exit(tavor_ks_info_t *ksi)
 718 {
 719         kt_did_t        tid;
 720 
 721         ASSERT(MUTEX_HELD(&ksi->tki_perfcntr64_lock));
 722 
 723         if (ksi->tki_perfcntr64_flags & TAVOR_PERFCNTR64_THREAD_CREATED) {
 724                 /*
 725                  * Signal the thread to exit and wait until the thread exits.
 726                  */
 727                 ksi->tki_perfcntr64_flags |= TAVOR_PERFCNTR64_THREAD_EXIT;
 728                 tid = ksi->tki_perfcntr64_thread_id;
 729                 cv_signal(&ksi->tki_perfcntr64_cv);
 730 
 731                 mutex_exit(&ksi->tki_perfcntr64_lock);
 732                 thread_join(tid);
 733                 mutex_enter(&ksi->tki_perfcntr64_lock);
 734         }
 735 }
 736 
 737 /*
 738  * tavor_kstat_perfcntr64_update()
 739  *    Context: Called from the kstat context
 740  *
 741  * See the general comment on 64 bit kstats for performance counters:
 742  */
 743 static int
 744 tavor_kstat_perfcntr64_update(kstat_t *ksp, int rw)
 745 {
 746         tavor_state_t                   *state;
 747         struct kstat_named              *data;
 748         tavor_ks_info_t         *ksi;
 749         tavor_perfcntr64_ks_info_t      *ksi64;
 750         int                             i, thr_exit;
 751 
 752         ksi64   = ksp->ks_private;
 753         state   = ksi64->tki64_state;
 754         ksi     = state->ts_ks_info;
 755         data    = (struct kstat_named *)(ksp->ks_data);
 756 
 757         mutex_enter(&ksi->tki_perfcntr64_lock);
 758 
 759         /*
 760          * 64 bit performance counters maintained by the software is not
 761          * enabled by default. Enable them upon a writing a non-zero value
 762          * to "enable" kstat. Disable them upon a writing zero to the
 763          * "enable" kstat.
 764          */
 765         if (rw == KSTAT_WRITE) {
 766                 if (data[TAVOR_PERFCNTR64_ENABLE_IDX].value.ui32) {
 767                         if (ksi64->tki64_enabled == 0) {
 768                                 /*
 769                                  * Reset the hardware counters to ensure that
 770                                  * the hardware counter doesn't max out
 771                                  * (and hence stop counting) before we get
 772                                  * a chance to reset the counter in
 773                                  * tavor_kstat_perfcntr64_update_thread.
 774                                  */
 775                                 if (tavor_getperfcntr_cmd_post(state,
 776                                     ksi64->tki64_port_num,
 777                                     TAVOR_CMD_NOSLEEP_SPIN, NULL, 1) !=
 778                                     TAVOR_CMD_SUCCESS) {
 779                                         mutex_exit(&ksi->tki_perfcntr64_lock);
 780                                         return (EIO);
 781                                 }
 782 
 783                                 /* Enable 64 bit software counters */
 784                                 ksi64->tki64_enabled = 1;
 785                                 for (i = 0;
 786                                     i < TAVOR_PERFCNTR64_NUM_COUNTERS; i++) {
 787                                         ksi64->tki64_counters[i] = 0;
 788                                         ksi64->tki64_last_read[i] = 0;
 789                                 }
 790                                 tavor_kstat_perfcntr64_thread_create(state);
 791                         }
 792 
 793                 } else if (ksi64->tki64_enabled) {
 794                         /* Disable 64 bit software counters */
 795                         ksi64->tki64_enabled = 0;
 796                         thr_exit = 1;
 797                         for (i = 0; i < state->ts_cfg_profile->cp_num_ports;
 798                             i++) {
 799                                 if (ksi->tki_perfcntr64[i].tki64_enabled) {
 800                                         thr_exit = 0;
 801                                         break;
 802                                 }
 803                         }
 804                         if (thr_exit)
 805                                 tavor_kstat_perfcntr64_thread_exit(ksi);
 806                 }
 807         } else if (ksi64->tki64_enabled) {
 808                 /*
 809                  * Read the counters and update kstats.
 810                  */
 811                 if (tavor_kstat_perfcntr64_read(state, ksi64->tki64_port_num,
 812                     0) != TAVOR_CMD_SUCCESS) {
 813                         mutex_exit(&ksi->tki_perfcntr64_lock);
 814                         return (EIO);
 815                 }
 816 
 817                 data[TAVOR_PERFCNTR64_ENABLE_IDX].value.ui32 = 1;
 818 
 819                 data[TAVOR_PERFCNTR64_XMIT_DATA_IDX].value.ui64 =
 820                     ksi64->tki64_counters[TAVOR_PERFCNTR64_XMIT_DATA_IDX] +
 821                     ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_DATA_IDX];
 822 
 823                 data[TAVOR_PERFCNTR64_RECV_DATA_IDX].value.ui64 =
 824                     ksi64->tki64_counters[TAVOR_PERFCNTR64_RECV_DATA_IDX] +
 825                     ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_DATA_IDX];
 826 
 827                 data[TAVOR_PERFCNTR64_XMIT_PKTS_IDX].value.ui64 =
 828                     ksi64->tki64_counters[TAVOR_PERFCNTR64_XMIT_PKTS_IDX] +
 829                     ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_PKTS_IDX];
 830 
 831                 data[TAVOR_PERFCNTR64_RECV_PKTS_IDX].value.ui64 =
 832                     ksi64->tki64_counters[TAVOR_PERFCNTR64_RECV_PKTS_IDX] +
 833                     ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_PKTS_IDX];
 834 
 835         } else {
 836                 /* return 0 in kstats if not enabled */
 837                 data[TAVOR_PERFCNTR64_ENABLE_IDX].value.ui32 = 0;
 838                 for (i = 1; i < TAVOR_PERFCNTR64_NUM_COUNTERS; i++)
 839                         data[i].value.ui64 = 0;
 840         }
 841 
 842         mutex_exit(&ksi->tki_perfcntr64_lock);
 843         return (0);
 844 }