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 } 982