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  * hermon_stats.c
  29  *    Hermon 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/hermon/hermon.h>
  43 
  44 static kstat_t *hermon_kstat_picN_create(hermon_state_t *state, int num_pic,
  45     int num_evt, hermon_ks_mask_t *ev_array);
  46 static kstat_t *hermon_kstat_cntr_create(hermon_state_t *state, int num_pic,
  47     int (*update)(kstat_t *, int));
  48 static int hermon_kstat_cntr_update(kstat_t *ksp, int rw);
  49 
  50 void hermon_kstat_perfcntr64_create(hermon_state_t *state, uint_t port_num);
  51 static int hermon_kstat_perfcntr64_read(hermon_state_t *state, uint_t port,
  52     int reset);
  53 static void hermon_kstat_perfcntr64_thread_exit(hermon_ks_info_t *ksi);
  54 static int hermon_kstat_perfcntr64_update(kstat_t *ksp, int rw);
  55 
  56 /*
  57  * Hermon 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 Hermon instance.
  60  */
  61 hermon_ks_mask_t hermon_ib_perfcnt_list[HERMON_CNTR_NUMENTRIES] = {
  62         {"port_xmit_data", 0, 0},
  63         {"port_recv_data", 0, 0},
  64         {"port_xmit_pkts", 0, 0},
  65         {"port_recv_pkts", 0, 0},
  66         {"port_recv_err", 0, 0},
  67         {"port_xmit_discards", 0, 0},
  68         {"vl15_dropped", 0, 0},
  69         {"port_xmit_wait", 0, 0},
  70         {"port_recv_remote_phys_err", 0, 0},
  71         {"port_xmit_constraint_err", 0, 0},
  72         {"port_recv_constraint_err", 0, 0},
  73         {"symbol_err_counter", 0, 0},
  74         {"link_err_recovery_cnt", 0, 0},
  75         {"link_downed_cnt", 0, 0},
  76         {"excessive_buffer_overruns", 0, 0},
  77         {"local_link_integrity_err", 0, 0},
  78         {"clear_pic", 0, 0}
  79 };
  80 
  81 /*
  82  * Return the maximum of (x) and (y)
  83  */
  84 #define MAX(x, y)       (((x) > (y)) ? (x) : (y))
  85 
  86 /*
  87  * Set (x) to the maximum of (x) and (y)
  88  */
  89 #define SET_TO_MAX(x, y)        \
  90 {                               \
  91         if ((x) < (y))               \
  92                 (x) = (y);      \
  93 }
  94 
  95 /*
  96  * hermon_kstat_init()
  97  *    Context: Only called from attach() path context
  98  */
  99 int
 100 hermon_kstat_init(hermon_state_t *state)
 101 {
 102         hermon_ks_info_t                *ksi;
 103         uint_t                  numports;
 104         int                     i;
 105 
 106         /* Allocate a kstat info structure */
 107         ksi = (hermon_ks_info_t *)kmem_zalloc(sizeof (hermon_ks_info_t),
 108             KM_SLEEP);
 109         if (ksi == NULL) {
 110                 return (DDI_FAILURE);
 111         }
 112         state->hs_ks_info = ksi;
 113 
 114         /*
 115          * Create as many "pic" and perfcntr64 kstats as we have IB ports.
 116          * Enable all of the events specified in the "hermon_ib_perfcnt_list"
 117          * structure.
 118          */
 119         numports = state->hs_cfg_profile->cp_num_ports;
 120         for (i = 0; i < numports; i++) {
 121                 ksi->hki_picN_ksp[i] = hermon_kstat_picN_create(state, i,
 122                     HERMON_CNTR_NUMENTRIES, hermon_ib_perfcnt_list);
 123                 if (ksi->hki_picN_ksp[i] == NULL) {
 124                         goto kstat_init_fail;
 125                 }
 126 
 127                 hermon_kstat_perfcntr64_create(state, i + 1);
 128                 if (ksi->hki_perfcntr64[i].hki64_ksp == NULL) {
 129                         goto kstat_init_fail;
 130                 }
 131         }
 132 
 133         /* Create the "counters" kstat too */
 134         ksi->hki_cntr_ksp = hermon_kstat_cntr_create(state, numports,
 135             hermon_kstat_cntr_update);
 136         if (ksi->hki_cntr_ksp == NULL) {
 137                 goto kstat_init_fail;
 138         }
 139 
 140         /* Initialize the control register and initial counter values */
 141         ksi->hki_pcr  = 0;
 142         ksi->hki_pic0 = 0;
 143         ksi->hki_pic1 = 0;
 144 
 145         /*
 146          * Initialize the Hermon hki_ib_perfcnt[] array values using the
 147          * default values in hermon_ib_perfcnt_list[]
 148          */
 149         for (i = 0; i < HERMON_CNTR_NUMENTRIES; i++) {
 150                 ksi->hki_ib_perfcnt[i] = hermon_ib_perfcnt_list[i];
 151         }
 152 
 153         mutex_init(&ksi->hki_perfcntr64_lock, NULL, MUTEX_DRIVER, NULL);
 154         cv_init(&ksi->hki_perfcntr64_cv, NULL, CV_DRIVER, NULL);
 155 
 156         return (DDI_SUCCESS);
 157 
 158 
 159 kstat_init_fail:
 160 
 161         /* Delete all the previously created kstats */
 162         if (ksi->hki_cntr_ksp != NULL) {
 163                 kstat_delete(ksi->hki_cntr_ksp);
 164         }
 165         for (i = 0; i < numports; i++) {
 166                 if (ksi->hki_picN_ksp[i] != NULL) {
 167                         kstat_delete(ksi->hki_picN_ksp[i]);
 168                 }
 169                 if (ksi->hki_perfcntr64[i].hki64_ksp != NULL) {
 170                         kstat_delete(ksi->hki_perfcntr64[i].hki64_ksp);
 171                 }
 172         }
 173 
 174         /* Free the kstat info structure */
 175         kmem_free(ksi, sizeof (hermon_ks_info_t));
 176 
 177         return (DDI_FAILURE);
 178 }
 179 
 180 
 181 /*
 182  * hermon_kstat_init()
 183  *    Context: Only called from attach() and/or detach() path contexts
 184  */
 185 void
 186 hermon_kstat_fini(hermon_state_t *state)
 187 {
 188         hermon_ks_info_t        *ksi;
 189         uint_t                  numports;
 190         int                     i;
 191 
 192         /* Get pointer to kstat info */
 193         ksi = state->hs_ks_info;
 194 
 195         /*
 196          * Signal the perfcntr64_update_thread to exit and wait until the
 197          * thread exits.
 198          */
 199         mutex_enter(&ksi->hki_perfcntr64_lock);
 200         hermon_kstat_perfcntr64_thread_exit(ksi);
 201         mutex_exit(&ksi->hki_perfcntr64_lock);
 202 
 203         /* Delete all the "pic" and perfcntr64 kstats (one per port) */
 204         numports = state->hs_cfg_profile->cp_num_ports;
 205         for (i = 0; i < numports; i++) {
 206                 if (ksi->hki_picN_ksp[i] != NULL) {
 207                         kstat_delete(ksi->hki_picN_ksp[i]);
 208                 }
 209 
 210                 if (ksi->hki_perfcntr64[i].hki64_ksp != NULL) {
 211                         kstat_delete(ksi->hki_perfcntr64[i].hki64_ksp);
 212                 }
 213         }
 214 
 215         /* Delete the "counter" kstats (one per port) */
 216         kstat_delete(ksi->hki_cntr_ksp);
 217 
 218         cv_destroy(&ksi->hki_perfcntr64_cv);
 219         mutex_destroy(&ksi->hki_perfcntr64_lock);
 220 
 221         /* Free the kstat info structure */
 222         kmem_free(ksi, sizeof (hermon_ks_info_t));
 223 }
 224 
 225 
 226 /*
 227  * hermon_kstat_picN_create()
 228  *    Context: Only called from attach() path context
 229  */
 230 static kstat_t *
 231 hermon_kstat_picN_create(hermon_state_t *state, int num_pic, int num_evt,
 232     hermon_ks_mask_t *ev_array)
 233 {
 234         kstat_t                 *picN_ksp;
 235         struct kstat_named      *pic_named_data;
 236         int                     drv_instance, i;
 237         char                    *drv_name;
 238         char                    pic_name[16];
 239 
 240         /*
 241          * Create the "picN" kstat.  In the steps, below we will attach
 242          * all of our named event types to it.
 243          */
 244         drv_name = (char *)ddi_driver_name(state->hs_dip);
 245         drv_instance = ddi_get_instance(state->hs_dip);
 246         (void) sprintf(pic_name, "pic%d", num_pic);
 247         picN_ksp = kstat_create(drv_name, drv_instance, pic_name, "bus",
 248             KSTAT_TYPE_NAMED, num_evt, NULL);
 249         if (picN_ksp == NULL) {
 250                 return (NULL);
 251         }
 252         pic_named_data = (struct kstat_named *)(picN_ksp->ks_data);
 253 
 254         /*
 255          * Write event names and their associated pcr masks. The last entry
 256          * in the array (clear_pic) is added separately below (as its pic
 257          * value must be inverted).
 258          */
 259         for (i = 0; i < num_evt - 1; i++) {
 260                 pic_named_data[i].value.ui64 =
 261                     ((uint64_t)i << (num_pic * HERMON_CNTR_SIZE));
 262                 kstat_named_init(&pic_named_data[i], ev_array[i].ks_evt_name,
 263                     KSTAT_DATA_UINT64);
 264         }
 265 
 266         /* Add the "clear_pic" entry */
 267         pic_named_data[i].value.ui64 =
 268             ~((uint64_t)HERMON_CNTR_MASK << (num_pic * HERMON_CNTR_SIZE));
 269         kstat_named_init(&pic_named_data[i], ev_array[i].ks_evt_name,
 270             KSTAT_DATA_UINT64);
 271 
 272         /* Install the kstat */
 273         kstat_install(picN_ksp);
 274 
 275         return (picN_ksp);
 276 }
 277 
 278 
 279 /*
 280  * hermon_kstat_cntr_create()
 281  *    Context: Only called from attach() path context
 282  */
 283 static kstat_t *
 284 hermon_kstat_cntr_create(hermon_state_t *state, int num_pic,
 285     int (*update)(kstat_t *, int))
 286 {
 287         struct kstat            *cntr_ksp;
 288         struct kstat_named      *cntr_named_data;
 289         int                     drv_instance, i;
 290         char                    *drv_name;
 291         char                    pic_str[16];
 292 
 293         /*
 294          * Create the "counters" kstat.  In the steps, below we will attach
 295          * all of our "pic" to it.   Note:  The size of this kstat is
 296          * num_pic + 1 because it also contains the "%pcr".
 297          */
 298         drv_name = (char *)ddi_driver_name(state->hs_dip);
 299         drv_instance = ddi_get_instance(state->hs_dip);
 300         cntr_ksp = kstat_create(drv_name, drv_instance, "counters", "bus",
 301             KSTAT_TYPE_NAMED, num_pic + 1, KSTAT_FLAG_WRITABLE);
 302         if (cntr_ksp == NULL) {
 303                 return (NULL);
 304         }
 305         cntr_named_data = (struct kstat_named *)(cntr_ksp->ks_data);
 306 
 307         /*
 308          * Initialize the named kstats (for the "pcr" and for the
 309          * individual "pic" kstats)
 310          */
 311         kstat_named_init(&cntr_named_data[0], "pcr", KSTAT_DATA_UINT64);
 312         for (i = 0; i < num_pic; i++) {
 313                 (void) sprintf(pic_str, "pic%d", i);
 314                 kstat_named_init(&cntr_named_data[i+1], pic_str,
 315                     KSTAT_DATA_UINT64);
 316         }
 317 
 318         /*
 319          * Store the Hermon softstate pointer in the kstat's private field so
 320          * that it is available to the update function.
 321          */
 322         cntr_ksp->ks_private = (void *)state;
 323         cntr_ksp->ks_update  = update;
 324 
 325         /* Install the kstat */
 326         kstat_install(cntr_ksp);
 327 
 328         return (cntr_ksp);
 329 }
 330 
 331 
 332 /*
 333  * hermon_kstat_cntr_update()
 334  *    Context: Called from the kstat context
 335  */
 336 static int
 337 hermon_kstat_cntr_update(kstat_t *ksp, int rw)
 338 {
 339         hermon_state_t          *state;
 340         hermon_ks_mask_t                *ib_perf;
 341         hermon_ks_info_t                *ksi;
 342         struct kstat_named      *data;
 343         uint64_t                pcr;
 344         uint32_t                tmp;
 345         uint32_t                oldval;
 346         uint_t                  numports, indx;
 347         int                     status;
 348         hermon_hw_sm_perfcntr_t sm_perfcntr;
 349 
 350         /*
 351          * Extract the Hermon softstate pointer, kstat data, pointer to the
 352          * kstat info structure, and pointer to the hki_ib_perfcnt[] array
 353          * from the input parameters.  Note: For warlock purposes, these
 354          * parameters are all accessed only in this routine and are,
 355          * therefore, protected by the lock used by the kstat framework.
 356          */
 357         state   = ksp->ks_private;
 358         data    = (struct kstat_named *)(ksp->ks_data);
 359         ksi     = state->hs_ks_info;
 360         ib_perf = &ksi->hki_ib_perfcnt[0];
 361         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ksi))
 362         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
 363         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ib_perf))
 364 
 365         /*
 366          * Depending on whether we are reading the "pic" counters or
 367          * writing the "pcr" control register, we need to handle and
 368          * fill in the kstat data appropriately.
 369          *
 370          * If this is a write to the "pcr", then extract the value from
 371          * the kstat data and store it in the kstat info structure.
 372          *
 373          * Otherwise, if this is a read of the "pic" counter(s), then
 374          * extract the register offset, size, and mask values from the
 375          * ib_perf[] array.  Then read the corresponding register and store
 376          * it into the kstat data.  Note:  We only read/fill in pic1 if more
 377          * than one port is configured.
 378          */
 379         numports = state->hs_cfg_profile->cp_num_ports;
 380         if (rw == KSTAT_WRITE) {
 381                 /* Update the stored "pcr" value */
 382                 ksi->hki_pcr = data[0].value.ui64;
 383                 return (0);
 384         } else {
 385                 /*
 386                  * Get the current "pcr" value and extract the lower
 387                  * portion (corresponding to the counters for "pic0")
 388                  */
 389                 pcr  = ksi->hki_pcr;
 390                 indx = pcr & HERMON_CNTR_MASK;
 391                 data[0].value.ui64 = pcr;
 392 
 393                 /*
 394                  * Fill in the "pic0" counter, corresponding to port 1.
 395                  * This involves reading in the current value in the register
 396                  * and calculating how many events have happened since this
 397                  * register was last polled.  Then we save away the current
 398                  * value for the counter and increment the "pic0" total by
 399                  * the number of new events.
 400                  */
 401                 oldval = ib_perf[indx].ks_old_pic0;
 402 
 403                 status = hermon_getperfcntr_cmd_post(state, 1,
 404                     HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
 405                 if (status != HERMON_CMD_SUCCESS) {
 406                         return (-1);
 407                 }
 408                 switch (indx) {
 409                 case 0:         /* port_xmit_data */
 410                         tmp = sm_perfcntr.portxmdata;
 411                         break;
 412                 case 1:         /* port_recv_data */
 413                         tmp = sm_perfcntr.portrcdata;
 414                         break;
 415                 case 2:         /* port_xmit_pkts */
 416                         tmp = sm_perfcntr.portxmpkts;
 417                         break;
 418                 case 3:         /* port_recv_pkts */
 419                         tmp = sm_perfcntr.portrcpkts;
 420                         break;
 421                 case 4:         /* port_recv_err */
 422                         tmp = sm_perfcntr.portrcv;
 423                         break;
 424                 case 5:         /* port_xmit_discards */
 425                         tmp = sm_perfcntr.portxmdiscard;
 426                         break;
 427                 case 6:         /* vl15_dropped */
 428                         tmp = sm_perfcntr.vl15drop;
 429                         break;
 430                 case 7:         /* port_xmit_wait */
 431                         tmp = sm_perfcntr.portxmwait;
 432                         break;
 433                 case 8:         /* port_recv_remote_phys_err */
 434                         tmp = sm_perfcntr.portrcvrem;
 435                         break;
 436                 case 9:         /* port_xmit_constraint_err */
 437                         tmp = sm_perfcntr.portxmconstr;
 438                         break;
 439                 case 10:        /* port_recv_constraint_err */
 440                         tmp = sm_perfcntr.portrcconstr;
 441                         break;
 442                 case 11:        /* symbol_err_counter */
 443                         tmp = sm_perfcntr.symerr;
 444                         break;
 445                 case 12:        /* link_err_recovery_cnt */
 446                         tmp = sm_perfcntr.linkerrrec;
 447                         break;
 448                 case 13:        /* link_downed_cnt */
 449                         tmp = sm_perfcntr.linkdown;
 450                         break;
 451                 case 14:        /* excessive_buffer_overruns */
 452                         tmp = sm_perfcntr.xsbuffovrun;
 453                         break;
 454                 case 15:        /* local_link_integrity_err */
 455                         tmp = sm_perfcntr.locallinkint;
 456                         break;
 457                 case 16:        /* clear_pic */
 458                         tmp = 0;        /* XXX */
 459                         break;
 460                 default:
 461                         cmn_err(CE_CONT, "perf counter out of range\n");
 462                 }
 463 
 464                 ib_perf[indx].ks_old_pic0 = tmp;
 465 
 466                 tmp = tmp - oldval;
 467                 ksi->hki_pic0 += tmp;
 468                 data[1].value.ui64 = ksi->hki_pic0;
 469 
 470                 /*
 471                  * If necessary, fill in the "pic1" counter for port 2.
 472                  * This works the same as above except that we extract the
 473                  * upper bits (corresponding to the counters for "pic1")
 474                  */
 475                 if (numports == HERMON_MAX_PORTS) {
 476                         indx   = pcr >> HERMON_CNTR_SIZE;
 477                         oldval = ib_perf[indx].ks_old_pic1;
 478 
 479                         status = hermon_getperfcntr_cmd_post(state, 2,
 480                             HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
 481                         if (status != HERMON_CMD_SUCCESS) {
 482                                 return (-1);
 483                         }
 484                         switch (indx) {
 485                         case 0:         /* port_xmit_data */
 486                                 tmp = sm_perfcntr.portxmdata;
 487                                 break;
 488                         case 1:         /* port_recv_data */
 489                                 tmp = sm_perfcntr.portrcdata;
 490                                 break;
 491                         case 2:         /* port_xmit_pkts */
 492                                 tmp = sm_perfcntr.portxmpkts;
 493                                 break;
 494                         case 3:         /* port_recv_pkts */
 495                                 tmp = sm_perfcntr.portrcpkts;
 496                                 break;
 497                         case 4:         /* port_recv_err */
 498                                 tmp = sm_perfcntr.portrcv;
 499                                 break;
 500                         case 5:         /* port_xmit_discards */
 501                                 tmp = sm_perfcntr.portxmdiscard;
 502                                 break;
 503                         case 6:         /* vl15_dropped */
 504                                 tmp = sm_perfcntr.vl15drop;
 505                                 break;
 506                         case 7:         /* port_xmit_wait */
 507                                 tmp = sm_perfcntr.portxmwait;
 508                                 break;
 509                         case 8:         /* port_recv_remote_phys_err */
 510                                 tmp = sm_perfcntr.portrcvrem;
 511                                 break;
 512                         case 9:         /* port_xmit_constraint_err */
 513                                 tmp = sm_perfcntr.portxmconstr;
 514                                 break;
 515                         case 10:        /* port_recv_constraint_err */
 516                                 tmp = sm_perfcntr.portrcconstr;
 517                                 break;
 518                         case 11:        /* symbol_err_counter */
 519                                 tmp = sm_perfcntr.symerr;
 520                                 break;
 521                         case 12:        /* link_err_recovery_cnt */
 522                                 tmp = sm_perfcntr.linkerrrec;
 523                                 break;
 524                         case 13:        /* link_downed_cnt */
 525                                 tmp = sm_perfcntr.linkdown;
 526                                 break;
 527                         case 14:        /* excessive_buffer_overruns */
 528                                 tmp = sm_perfcntr.xsbuffovrun;
 529                                 break;
 530                         case 15:        /* local_link_integrity_err */
 531                                 tmp = sm_perfcntr.locallinkint;
 532                                 break;
 533                         case 16:        /* clear_pic */
 534                                 tmp = 0;        /* XXX */
 535                                 break;
 536                         default:
 537                                 cmn_err(CE_CONT, "perf counter out of range\n");
 538                         }
 539 
 540                         ib_perf[indx].ks_old_pic1 = tmp;
 541 
 542                         tmp = tmp - oldval;
 543                         ksi->hki_pic1 += tmp;
 544                         data[2].value.ui64 = ksi->hki_pic1;
 545                 }
 546 
 547                 return (0);
 548         }
 549 }
 550 
 551 /*
 552  * 64 bit kstats for performance counters:
 553  *
 554  * Export 64 bit performance counters in kstats.
 555  *
 556  * If the HCA hardware supports 64 bit extended port counters, we use the
 557  * hardware based counters. If the HCA hardware does not support extended port
 558  * counters, we maintain 64 bit performance counters in software using the
 559  * 32 bit hardware port counters.
 560  *
 561  * The software based counters are maintained as follows:
 562  *
 563  * We create a thread that, every one second, reads the values of 32 bit
 564  * hardware counters and adds them to the 64 bit software counters. Immediately
 565  * after reading, it resets the 32 bit hardware counters to zero (so that they
 566  * start counting from zero again). At any time the current value of a counter
 567  * is going to be the sum of the 64 bit software counter and the 32 bit
 568  * hardware counter.
 569  *
 570  * Since this work need not be done if there is no consumer, by default
 571  * we do not maintain 64 bit software counters. To enable this the consumer
 572  * needs to write a non-zero value to the "enable" component of the of
 573  * perf_counters kstat. Writing zero to this component will disable this work.
 574  * NOTE: The enabling or disabling applies to software based counters only.
 575  * Hardware based counters counters are always enabled.
 576  *
 577  * If performance monitor is enabled in subnet manager, the SM could
 578  * periodically reset the hardware counters by sending perf-MADs. So only
 579  * one of either our software 64 bit counters or the SM performance monitor
 580  * could be enabled at the same time. However, if both of them are enabled at
 581  * the same time we still do our best by keeping track of the values of the
 582  * last read 32 bit hardware counters. If the current read of a 32 bit hardware
 583  * counter is less than the last read of the counter, we ignore the current
 584  * value and go with the last read value.
 585  */
 586 
 587 /*
 588  * hermon_kstat_perfcntr64_create()
 589  *    Context: Only called from attach() path context
 590  *
 591  * Create "port#/perf_counters" kstat for the specified port number.
 592  */
 593 void
 594 hermon_kstat_perfcntr64_create(hermon_state_t *state, uint_t port_num)
 595 {
 596         hermon_ks_info_t        *ksi = state->hs_ks_info;
 597         struct kstat            *cntr_ksp;
 598         struct kstat_named      *cntr_named_data;
 599         int                     drv_instance;
 600         char                    *drv_name;
 601         char                    kname[32];
 602         int                     status, ext_width_supported;
 603 
 604         ASSERT(port_num != 0);
 605 
 606         status = hermon_is_ext_port_counters_supported(state, port_num,
 607             HERMON_CMD_NOSLEEP_SPIN, &ext_width_supported);
 608         if (status == HERMON_CMD_SUCCESS) {
 609                 ksi->hki_perfcntr64[port_num - 1].
 610                     hki64_ext_port_counters_supported = ext_width_supported;
 611         }
 612 
 613         drv_name = (char *)ddi_driver_name(state->hs_dip);
 614         drv_instance = ddi_get_instance(state->hs_dip);
 615         (void) snprintf(kname, sizeof (kname), "port%u/perf_counters",
 616             port_num);
 617         cntr_ksp = kstat_create(drv_name, drv_instance, kname, "ib",
 618             KSTAT_TYPE_NAMED, HERMON_PERFCNTR64_NUM_COUNTERS,
 619             KSTAT_FLAG_WRITABLE);
 620         if (cntr_ksp == NULL) {
 621                 return;
 622         }
 623         cntr_named_data = (struct kstat_named *)(cntr_ksp->ks_data);
 624 
 625         kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_ENABLE_IDX],
 626             "enable", KSTAT_DATA_UINT32);
 627         kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_XMIT_DATA_IDX],
 628             "xmit_data", KSTAT_DATA_UINT64);
 629         kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_RECV_DATA_IDX],
 630             "recv_data", KSTAT_DATA_UINT64);
 631         kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_XMIT_PKTS_IDX],
 632             "xmit_pkts", KSTAT_DATA_UINT64);
 633         kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_RECV_PKTS_IDX],
 634             "recv_pkts", KSTAT_DATA_UINT64);
 635 
 636         ksi->hki_perfcntr64[port_num - 1].hki64_ksp = cntr_ksp;
 637         ksi->hki_perfcntr64[port_num - 1].hki64_port_num = port_num;
 638         ksi->hki_perfcntr64[port_num - 1].hki64_state = state;
 639 
 640         cntr_ksp->ks_private = &ksi->hki_perfcntr64[port_num - 1];
 641         cntr_ksp->ks_update  = hermon_kstat_perfcntr64_update;
 642 
 643         /* Install the kstat */
 644         kstat_install(cntr_ksp);
 645 }
 646 
 647 /*
 648  * hermon_kstat_perfcntr64_read()
 649  *
 650  * Read the values of 32 bit hardware counters.
 651  *
 652  * If reset is true, reset the 32 bit hardware counters. Add the values of the
 653  * 32 bit hardware counters to the 64 bit software counters.
 654  *
 655  * If reset is false, just save the values read from the 32 bit hardware
 656  * counters in hki64_last_read[].
 657  *
 658  * See the general comment on the 64 bit performance counters
 659  * regarding the use of last read 32 bit hardware counter values.
 660  */
 661 static int
 662 hermon_kstat_perfcntr64_read(hermon_state_t *state, uint_t port, int reset)
 663 {
 664         hermon_ks_info_t        *ksi = state->hs_ks_info;
 665         hermon_perfcntr64_ks_info_t *ksi64 = &ksi->hki_perfcntr64[port - 1];
 666         int                     status, i;
 667         uint32_t                tmp;
 668         hermon_hw_sm_perfcntr_t sm_perfcntr;
 669 
 670         ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock));
 671         ASSERT(port != 0);
 672 
 673         /* read the 32 bit hardware counters */
 674         status = hermon_getperfcntr_cmd_post(state, port,
 675             HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
 676         if (status != HERMON_CMD_SUCCESS) {
 677                 return (status);
 678         }
 679 
 680         if (reset) {
 681                 /* reset the hardware counters */
 682                 status = hermon_getperfcntr_cmd_post(state, port,
 683                     HERMON_CMD_NOSLEEP_SPIN, NULL, 1);
 684                 if (status != HERMON_CMD_SUCCESS) {
 685                         return (status);
 686                 }
 687 
 688                 /*
 689                  * Update 64 bit software counters
 690                  */
 691                 tmp = MAX(sm_perfcntr.portxmdata,
 692                     ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX]);
 693                 ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_DATA_IDX] += tmp;
 694 
 695                 tmp = MAX(sm_perfcntr.portrcdata,
 696                     ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX]);
 697                 ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_DATA_IDX] += tmp;
 698 
 699                 tmp = MAX(sm_perfcntr.portxmpkts,
 700                     ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX]);
 701                 ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_PKTS_IDX] += tmp;
 702 
 703                 tmp = MAX(sm_perfcntr.portrcpkts,
 704                     ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX]);
 705                 ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_PKTS_IDX] += tmp;
 706 
 707                 for (i = 0; i < HERMON_PERFCNTR64_NUM_COUNTERS; i++)
 708                         ksi64->hki64_last_read[i] = 0;
 709 
 710         } else {
 711                 /*
 712                  * Update ksi64->hki64_last_read[]
 713                  */
 714                 SET_TO_MAX(
 715                     ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX],
 716                     sm_perfcntr.portxmdata);
 717 
 718                 SET_TO_MAX(
 719                     ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX],
 720                     sm_perfcntr.portrcdata);
 721 
 722                 SET_TO_MAX(
 723                     ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX],
 724                     sm_perfcntr.portxmpkts);
 725 
 726                 SET_TO_MAX(
 727                     ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX],
 728                     sm_perfcntr.portrcpkts);
 729         }
 730 
 731         return (HERMON_CMD_SUCCESS);
 732 }
 733 
 734 /*
 735  * hermon_kstat_perfcntr64_update_thread()
 736  *    Context: Entry point for a kernel thread
 737  *
 738  * Maintain 64 bit performance counters in software using the 32 bit
 739  * hardware counters.
 740  */
 741 static void
 742 hermon_kstat_perfcntr64_update_thread(void *arg)
 743 {
 744         hermon_state_t          *state = (hermon_state_t *)arg;
 745         hermon_ks_info_t        *ksi = state->hs_ks_info;
 746         uint_t                  i;
 747         clock_t                 delta = drv_usectohz(1000000);
 748 
 749         mutex_enter(&ksi->hki_perfcntr64_lock);
 750         /*
 751          * Every one second update the values 64 bit software counters
 752          * for all ports. Exit if HERMON_PERFCNTR64_THREAD_EXIT flag is set.
 753          */
 754         while (!(ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_EXIT)) {
 755                 for (i = 0; i < state->hs_cfg_profile->cp_num_ports; i++) {
 756                         if (ksi->hki_perfcntr64[i].hki64_enabled) {
 757                                 (void) hermon_kstat_perfcntr64_read(state,
 758                                     i + 1, 1);
 759                         }
 760                 }
 761                 /* sleep for a second */
 762                 (void) cv_reltimedwait(&ksi->hki_perfcntr64_cv,
 763                     &ksi->hki_perfcntr64_lock, delta, TR_CLOCK_TICK);
 764         }
 765         ksi->hki_perfcntr64_flags = 0;
 766         mutex_exit(&ksi->hki_perfcntr64_lock);
 767 }
 768 
 769 /*
 770  * hermon_kstat_perfcntr64_thread_create()
 771  *    Context: Called from the kstat context
 772  *
 773  * Create a thread that maintains 64 bit performance counters in software.
 774  */
 775 static void
 776 hermon_kstat_perfcntr64_thread_create(hermon_state_t *state)
 777 {
 778         hermon_ks_info_t        *ksi = state->hs_ks_info;
 779         kthread_t               *thr;
 780 
 781         ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock));
 782 
 783         /*
 784          * One thread per hermon instance. Don't create a thread if already
 785          * created.
 786          */
 787         if (!(ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_CREATED)) {
 788                 thr = thread_create(NULL, 0,
 789                     hermon_kstat_perfcntr64_update_thread,
 790                     state, 0, &p0, TS_RUN, minclsyspri);
 791                 ksi->hki_perfcntr64_thread_id = thr->t_did;
 792                 ksi->hki_perfcntr64_flags |= HERMON_PERFCNTR64_THREAD_CREATED;
 793         }
 794 }
 795 
 796 /*
 797  * hermon_kstat_perfcntr64_thread_exit()
 798  *    Context: Called from attach, detach or kstat context
 799  */
 800 static void
 801 hermon_kstat_perfcntr64_thread_exit(hermon_ks_info_t *ksi)
 802 {
 803         kt_did_t        tid;
 804 
 805         ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock));
 806 
 807         if (ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_CREATED) {
 808                 /*
 809                  * Signal the thread to exit and wait until the thread exits.
 810                  */
 811                 ksi->hki_perfcntr64_flags |= HERMON_PERFCNTR64_THREAD_EXIT;
 812                 tid = ksi->hki_perfcntr64_thread_id;
 813                 cv_signal(&ksi->hki_perfcntr64_cv);
 814 
 815                 mutex_exit(&ksi->hki_perfcntr64_lock);
 816                 thread_join(tid);
 817                 mutex_enter(&ksi->hki_perfcntr64_lock);
 818         }
 819 }
 820 
 821 /*
 822  * hermon_kstat_perfcntr64_update_ext()
 823  *    Context: Called from the kstat context
 824  *
 825  * Update perf_counters kstats with the values of the extended port counters
 826  * from the hardware.
 827  */
 828 static int
 829 hermon_kstat_perfcntr64_update_ext(hermon_perfcntr64_ks_info_t *ksi64, int rw,
 830     struct kstat_named *data)
 831 {
 832         hermon_hw_sm_extperfcntr_t      sm_extperfcntr;
 833 
 834         /*
 835          * The "enable" component of the kstat is the only writable kstat.
 836          * It is a no-op when the hardware supports extended port counters.
 837          */
 838         if (rw == KSTAT_WRITE)
 839                 return (0);
 840 
 841         /*
 842          * Read the counters and update kstats.
 843          */
 844         if (hermon_getextperfcntr_cmd_post(ksi64->hki64_state,
 845             ksi64->hki64_port_num, HERMON_CMD_NOSLEEP_SPIN, &sm_extperfcntr) !=
 846             HERMON_CMD_SUCCESS) {
 847                 return (EIO);
 848         }
 849 
 850         data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 1;
 851 
 852         data[HERMON_PERFCNTR64_XMIT_DATA_IDX].value.ui64 =
 853             sm_extperfcntr.portxmdata;
 854 
 855         data[HERMON_PERFCNTR64_RECV_DATA_IDX].value.ui64 =
 856             sm_extperfcntr.portrcdata;
 857 
 858         data[HERMON_PERFCNTR64_XMIT_PKTS_IDX].value.ui64 =
 859             sm_extperfcntr.portxmpkts;
 860 
 861         data[HERMON_PERFCNTR64_RECV_PKTS_IDX].value.ui64 =
 862             sm_extperfcntr.portrcpkts;
 863 
 864         return (0);
 865 }
 866 
 867 /*
 868  * hermon_kstat_perfcntr64_update()
 869  *    Context: Called from the kstat context
 870  *
 871  * See the general comment on 64 bit kstats for performance counters:
 872  */
 873 static int
 874 hermon_kstat_perfcntr64_update(kstat_t *ksp, int rw)
 875 {
 876         hermon_state_t                  *state;
 877         struct kstat_named              *data;
 878         hermon_ks_info_t                *ksi;
 879         hermon_perfcntr64_ks_info_t     *ksi64;
 880         int                             i, thr_exit;
 881         int                             rv;
 882 
 883         ksi64   = ksp->ks_private;
 884         state   = ksi64->hki64_state;
 885         ksi     = state->hs_ks_info;
 886         data    = (struct kstat_named *)(ksp->ks_data);
 887 
 888         mutex_enter(&ksi->hki_perfcntr64_lock);
 889 
 890         if (ksi64->hki64_ext_port_counters_supported) {
 891                 rv = hermon_kstat_perfcntr64_update_ext(ksi64, rw, data);
 892                 mutex_exit(&ksi->hki_perfcntr64_lock);
 893                 return (rv);
 894         }
 895 
 896         /*
 897          * 64 bit performance counters maintained by the software is not
 898          * enabled by default. Enable them upon a writing a non-zero value
 899          * to "enable" kstat. Disable them upon a writing zero to the
 900          * "enable" kstat.
 901          */
 902         if (rw == KSTAT_WRITE) {
 903                 if (data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32) {
 904                         if (ksi64->hki64_enabled == 0) {
 905                                 /*
 906                                  * Reset the hardware counters to ensure that
 907                                  * the hardware counter doesn't max out
 908                                  * (and hence stop counting) before we get
 909                                  * a chance to reset the counter in
 910                                  * hermon_kstat_perfcntr64_update_thread.
 911                                  */
 912                                 if (hermon_getperfcntr_cmd_post(state,
 913                                     ksi64->hki64_port_num,
 914                                     HERMON_CMD_NOSLEEP_SPIN, NULL, 1) !=
 915                                     HERMON_CMD_SUCCESS) {
 916                                         mutex_exit(&ksi->hki_perfcntr64_lock);
 917                                         return (EIO);
 918                                 }
 919 
 920                                 /* Enable 64 bit software counters */
 921                                 ksi64->hki64_enabled = 1;
 922                                 for (i = 0;
 923                                     i < HERMON_PERFCNTR64_NUM_COUNTERS; i++) {
 924                                         ksi64->hki64_counters[i] = 0;
 925                                         ksi64->hki64_last_read[i] = 0;
 926                                 }
 927                                 hermon_kstat_perfcntr64_thread_create(state);
 928                         }
 929 
 930                 } else if (ksi64->hki64_enabled) {
 931                         /* Disable 64 bit software counters */
 932                         ksi64->hki64_enabled = 0;
 933                         thr_exit = 1;
 934                         for (i = 0; i < state->hs_cfg_profile->cp_num_ports;
 935                             i++) {
 936                                 if (ksi->hki_perfcntr64[i].hki64_enabled) {
 937                                         thr_exit = 0;
 938                                         break;
 939                                 }
 940                         }
 941                         if (thr_exit)
 942                                 hermon_kstat_perfcntr64_thread_exit(ksi);
 943                 }
 944         } else if (ksi64->hki64_enabled) {
 945                 /*
 946                  * Read the counters and update kstats.
 947                  */
 948                 if (hermon_kstat_perfcntr64_read(state, ksi64->hki64_port_num,
 949                     0) != HERMON_CMD_SUCCESS) {
 950                         mutex_exit(&ksi->hki_perfcntr64_lock);
 951                         return (EIO);
 952                 }
 953 
 954                 data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 1;
 955 
 956                 data[HERMON_PERFCNTR64_XMIT_DATA_IDX].value.ui64 =
 957                     ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_DATA_IDX] +
 958                     ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX];
 959 
 960                 data[HERMON_PERFCNTR64_RECV_DATA_IDX].value.ui64 =
 961                     ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_DATA_IDX] +
 962                     ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX];
 963 
 964                 data[HERMON_PERFCNTR64_XMIT_PKTS_IDX].value.ui64 =
 965                     ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_PKTS_IDX] +
 966                     ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX];
 967 
 968                 data[HERMON_PERFCNTR64_RECV_PKTS_IDX].value.ui64 =
 969                     ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_PKTS_IDX] +
 970                     ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX];
 971 
 972         } else {
 973                 /* return 0 in kstats if not enabled */
 974                 data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 0;
 975                 for (i = 1; i < HERMON_PERFCNTR64_NUM_COUNTERS; i++)
 976                         data[i].value.ui64 = 0;
 977         }
 978 
 979         mutex_exit(&ksi->hki_perfcntr64_lock);
 980         return (0);
 981 }