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. 354 */ 355 state = ksp->ks_private; 356 data = (struct kstat_named *)(ksp->ks_data); 357 ksi = state->hs_ks_info; 358 ib_perf = &ksi->hki_ib_perfcnt[0]; 359 360 /* 361 * Depending on whether we are reading the "pic" counters or 362 * writing the "pcr" control register, we need to handle and 363 * fill in the kstat data appropriately. 364 * 365 * If this is a write to the "pcr", then extract the value from 366 * the kstat data and store it in the kstat info structure. 367 * 368 * Otherwise, if this is a read of the "pic" counter(s), then 369 * extract the register offset, size, and mask values from the 370 * ib_perf[] array. Then read the corresponding register and store 371 * it into the kstat data. Note: We only read/fill in pic1 if more 372 * than one port is configured. 373 */ 374 numports = state->hs_cfg_profile->cp_num_ports; 375 if (rw == KSTAT_WRITE) { 376 /* Update the stored "pcr" value */ 377 ksi->hki_pcr = data[0].value.ui64; 378 return (0); 379 } else { 380 /* 381 * Get the current "pcr" value and extract the lower 382 * portion (corresponding to the counters for "pic0") 383 */ 384 pcr = ksi->hki_pcr; 385 indx = pcr & HERMON_CNTR_MASK; 386 data[0].value.ui64 = pcr; 387 388 /* 389 * Fill in the "pic0" counter, corresponding to port 1. 390 * This involves reading in the current value in the register 391 * and calculating how many events have happened since this 392 * register was last polled. Then we save away the current 393 * value for the counter and increment the "pic0" total by 394 * the number of new events. 395 */ 396 oldval = ib_perf[indx].ks_old_pic0; 397 398 status = hermon_getperfcntr_cmd_post(state, 1, 399 HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0); 400 if (status != HERMON_CMD_SUCCESS) { 401 return (-1); 402 } 403 switch (indx) { 404 case 0: /* port_xmit_data */ 405 tmp = sm_perfcntr.portxmdata; 406 break; 407 case 1: /* port_recv_data */ 408 tmp = sm_perfcntr.portrcdata; 409 break; 410 case 2: /* port_xmit_pkts */ 411 tmp = sm_perfcntr.portxmpkts; 412 break; 413 case 3: /* port_recv_pkts */ 414 tmp = sm_perfcntr.portrcpkts; 415 break; 416 case 4: /* port_recv_err */ 417 tmp = sm_perfcntr.portrcv; 418 break; 419 case 5: /* port_xmit_discards */ 420 tmp = sm_perfcntr.portxmdiscard; 421 break; 422 case 6: /* vl15_dropped */ 423 tmp = sm_perfcntr.vl15drop; 424 break; 425 case 7: /* port_xmit_wait */ 426 tmp = sm_perfcntr.portxmwait; 427 break; 428 case 8: /* port_recv_remote_phys_err */ 429 tmp = sm_perfcntr.portrcvrem; 430 break; 431 case 9: /* port_xmit_constraint_err */ 432 tmp = sm_perfcntr.portxmconstr; 433 break; 434 case 10: /* port_recv_constraint_err */ 435 tmp = sm_perfcntr.portrcconstr; 436 break; 437 case 11: /* symbol_err_counter */ 438 tmp = sm_perfcntr.symerr; 439 break; 440 case 12: /* link_err_recovery_cnt */ 441 tmp = sm_perfcntr.linkerrrec; 442 break; 443 case 13: /* link_downed_cnt */ 444 tmp = sm_perfcntr.linkdown; 445 break; 446 case 14: /* excessive_buffer_overruns */ 447 tmp = sm_perfcntr.xsbuffovrun; 448 break; 449 case 15: /* local_link_integrity_err */ 450 tmp = sm_perfcntr.locallinkint; 451 break; 452 case 16: /* clear_pic */ 453 tmp = 0; /* XXX */ 454 break; 455 default: 456 cmn_err(CE_CONT, "perf counter out of range\n"); 457 } 458 459 ib_perf[indx].ks_old_pic0 = tmp; 460 461 tmp = tmp - oldval; 462 ksi->hki_pic0 += tmp; 463 data[1].value.ui64 = ksi->hki_pic0; 464 465 /* 466 * If necessary, fill in the "pic1" counter for port 2. 467 * This works the same as above except that we extract the 468 * upper bits (corresponding to the counters for "pic1") 469 */ 470 if (numports == HERMON_MAX_PORTS) { 471 indx = pcr >> HERMON_CNTR_SIZE; 472 oldval = ib_perf[indx].ks_old_pic1; 473 474 status = hermon_getperfcntr_cmd_post(state, 2, 475 HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0); 476 if (status != HERMON_CMD_SUCCESS) { 477 return (-1); 478 } 479 switch (indx) { 480 case 0: /* port_xmit_data */ 481 tmp = sm_perfcntr.portxmdata; 482 break; 483 case 1: /* port_recv_data */ 484 tmp = sm_perfcntr.portrcdata; 485 break; 486 case 2: /* port_xmit_pkts */ 487 tmp = sm_perfcntr.portxmpkts; 488 break; 489 case 3: /* port_recv_pkts */ 490 tmp = sm_perfcntr.portrcpkts; 491 break; 492 case 4: /* port_recv_err */ 493 tmp = sm_perfcntr.portrcv; 494 break; 495 case 5: /* port_xmit_discards */ 496 tmp = sm_perfcntr.portxmdiscard; 497 break; 498 case 6: /* vl15_dropped */ 499 tmp = sm_perfcntr.vl15drop; 500 break; 501 case 7: /* port_xmit_wait */ 502 tmp = sm_perfcntr.portxmwait; 503 break; 504 case 8: /* port_recv_remote_phys_err */ 505 tmp = sm_perfcntr.portrcvrem; 506 break; 507 case 9: /* port_xmit_constraint_err */ 508 tmp = sm_perfcntr.portxmconstr; 509 break; 510 case 10: /* port_recv_constraint_err */ 511 tmp = sm_perfcntr.portrcconstr; 512 break; 513 case 11: /* symbol_err_counter */ 514 tmp = sm_perfcntr.symerr; 515 break; 516 case 12: /* link_err_recovery_cnt */ 517 tmp = sm_perfcntr.linkerrrec; 518 break; 519 case 13: /* link_downed_cnt */ 520 tmp = sm_perfcntr.linkdown; 521 break; 522 case 14: /* excessive_buffer_overruns */ 523 tmp = sm_perfcntr.xsbuffovrun; 524 break; 525 case 15: /* local_link_integrity_err */ 526 tmp = sm_perfcntr.locallinkint; 527 break; 528 case 16: /* clear_pic */ 529 tmp = 0; /* XXX */ 530 break; 531 default: 532 cmn_err(CE_CONT, "perf counter out of range\n"); 533 } 534 535 ib_perf[indx].ks_old_pic1 = tmp; 536 537 tmp = tmp - oldval; 538 ksi->hki_pic1 += tmp; 539 data[2].value.ui64 = ksi->hki_pic1; 540 } 541 542 return (0); 543 } 544 } 545 546 /* 547 * 64 bit kstats for performance counters: 548 * 549 * Export 64 bit performance counters in kstats. 550 * 551 * If the HCA hardware supports 64 bit extended port counters, we use the 552 * hardware based counters. If the HCA hardware does not support extended port 553 * counters, we maintain 64 bit performance counters in software using the 554 * 32 bit hardware port counters. 555 * 556 * The software based counters are maintained as follows: 557 * 558 * We create a thread that, every one second, reads the values of 32 bit 559 * hardware counters and adds them to the 64 bit software counters. Immediately 560 * after reading, it resets the 32 bit hardware counters to zero (so that they 561 * start counting from zero again). At any time the current value of a counter 562 * is going to be the sum of the 64 bit software counter and the 32 bit 563 * hardware counter. 564 * 565 * Since this work need not be done if there is no consumer, by default 566 * we do not maintain 64 bit software counters. To enable this the consumer 567 * needs to write a non-zero value to the "enable" component of the of 568 * perf_counters kstat. Writing zero to this component will disable this work. 569 * NOTE: The enabling or disabling applies to software based counters only. 570 * Hardware based counters counters are always enabled. 571 * 572 * If performance monitor is enabled in subnet manager, the SM could 573 * periodically reset the hardware counters by sending perf-MADs. So only 574 * one of either our software 64 bit counters or the SM performance monitor 575 * could be enabled at the same time. However, if both of them are enabled at 576 * the same time we still do our best by keeping track of the values of the 577 * last read 32 bit hardware counters. If the current read of a 32 bit hardware 578 * counter is less than the last read of the counter, we ignore the current 579 * value and go with the last read value. 580 */ 581 582 /* 583 * hermon_kstat_perfcntr64_create() 584 * Context: Only called from attach() path context 585 * 586 * Create "port#/perf_counters" kstat for the specified port number. 587 */ 588 void 589 hermon_kstat_perfcntr64_create(hermon_state_t *state, uint_t port_num) 590 { 591 hermon_ks_info_t *ksi = state->hs_ks_info; 592 struct kstat *cntr_ksp; 593 struct kstat_named *cntr_named_data; 594 int drv_instance; 595 char *drv_name; 596 char kname[32]; 597 int status, ext_width_supported; 598 599 ASSERT(port_num != 0); 600 601 status = hermon_is_ext_port_counters_supported(state, port_num, 602 HERMON_CMD_NOSLEEP_SPIN, &ext_width_supported); 603 if (status == HERMON_CMD_SUCCESS) { 604 ksi->hki_perfcntr64[port_num - 1]. 605 hki64_ext_port_counters_supported = ext_width_supported; 606 } 607 608 drv_name = (char *)ddi_driver_name(state->hs_dip); 609 drv_instance = ddi_get_instance(state->hs_dip); 610 (void) snprintf(kname, sizeof (kname), "port%u/perf_counters", 611 port_num); 612 cntr_ksp = kstat_create(drv_name, drv_instance, kname, "ib", 613 KSTAT_TYPE_NAMED, HERMON_PERFCNTR64_NUM_COUNTERS, 614 KSTAT_FLAG_WRITABLE); 615 if (cntr_ksp == NULL) { 616 return; 617 } 618 cntr_named_data = (struct kstat_named *)(cntr_ksp->ks_data); 619 620 kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_ENABLE_IDX], 621 "enable", KSTAT_DATA_UINT32); 622 kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_XMIT_DATA_IDX], 623 "xmit_data", KSTAT_DATA_UINT64); 624 kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_RECV_DATA_IDX], 625 "recv_data", KSTAT_DATA_UINT64); 626 kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_XMIT_PKTS_IDX], 627 "xmit_pkts", KSTAT_DATA_UINT64); 628 kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_RECV_PKTS_IDX], 629 "recv_pkts", KSTAT_DATA_UINT64); 630 631 ksi->hki_perfcntr64[port_num - 1].hki64_ksp = cntr_ksp; 632 ksi->hki_perfcntr64[port_num - 1].hki64_port_num = port_num; 633 ksi->hki_perfcntr64[port_num - 1].hki64_state = state; 634 635 cntr_ksp->ks_private = &ksi->hki_perfcntr64[port_num - 1]; 636 cntr_ksp->ks_update = hermon_kstat_perfcntr64_update; 637 638 /* Install the kstat */ 639 kstat_install(cntr_ksp); 640 } 641 642 /* 643 * hermon_kstat_perfcntr64_read() 644 * 645 * Read the values of 32 bit hardware counters. 646 * 647 * If reset is true, reset the 32 bit hardware counters. Add the values of the 648 * 32 bit hardware counters to the 64 bit software counters. 649 * 650 * If reset is false, just save the values read from the 32 bit hardware 651 * counters in hki64_last_read[]. 652 * 653 * See the general comment on the 64 bit performance counters 654 * regarding the use of last read 32 bit hardware counter values. 655 */ 656 static int 657 hermon_kstat_perfcntr64_read(hermon_state_t *state, uint_t port, int reset) 658 { 659 hermon_ks_info_t *ksi = state->hs_ks_info; 660 hermon_perfcntr64_ks_info_t *ksi64 = &ksi->hki_perfcntr64[port - 1]; 661 int status, i; 662 uint32_t tmp; 663 hermon_hw_sm_perfcntr_t sm_perfcntr; 664 665 ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock)); 666 ASSERT(port != 0); 667 668 /* read the 32 bit hardware counters */ 669 status = hermon_getperfcntr_cmd_post(state, port, 670 HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0); 671 if (status != HERMON_CMD_SUCCESS) { 672 return (status); 673 } 674 675 if (reset) { 676 /* reset the hardware counters */ 677 status = hermon_getperfcntr_cmd_post(state, port, 678 HERMON_CMD_NOSLEEP_SPIN, NULL, 1); 679 if (status != HERMON_CMD_SUCCESS) { 680 return (status); 681 } 682 683 /* 684 * Update 64 bit software counters 685 */ 686 tmp = MAX(sm_perfcntr.portxmdata, 687 ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX]); 688 ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_DATA_IDX] += tmp; 689 690 tmp = MAX(sm_perfcntr.portrcdata, 691 ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX]); 692 ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_DATA_IDX] += tmp; 693 694 tmp = MAX(sm_perfcntr.portxmpkts, 695 ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX]); 696 ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_PKTS_IDX] += tmp; 697 698 tmp = MAX(sm_perfcntr.portrcpkts, 699 ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX]); 700 ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_PKTS_IDX] += tmp; 701 702 for (i = 0; i < HERMON_PERFCNTR64_NUM_COUNTERS; i++) 703 ksi64->hki64_last_read[i] = 0; 704 705 } else { 706 /* 707 * Update ksi64->hki64_last_read[] 708 */ 709 SET_TO_MAX( 710 ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX], 711 sm_perfcntr.portxmdata); 712 713 SET_TO_MAX( 714 ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX], 715 sm_perfcntr.portrcdata); 716 717 SET_TO_MAX( 718 ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX], 719 sm_perfcntr.portxmpkts); 720 721 SET_TO_MAX( 722 ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX], 723 sm_perfcntr.portrcpkts); 724 } 725 726 return (HERMON_CMD_SUCCESS); 727 } 728 729 /* 730 * hermon_kstat_perfcntr64_update_thread() 731 * Context: Entry point for a kernel thread 732 * 733 * Maintain 64 bit performance counters in software using the 32 bit 734 * hardware counters. 735 */ 736 static void 737 hermon_kstat_perfcntr64_update_thread(void *arg) 738 { 739 hermon_state_t *state = (hermon_state_t *)arg; 740 hermon_ks_info_t *ksi = state->hs_ks_info; 741 uint_t i; 742 clock_t delta = drv_usectohz(1000000); 743 744 mutex_enter(&ksi->hki_perfcntr64_lock); 745 /* 746 * Every one second update the values 64 bit software counters 747 * for all ports. Exit if HERMON_PERFCNTR64_THREAD_EXIT flag is set. 748 */ 749 while (!(ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_EXIT)) { 750 for (i = 0; i < state->hs_cfg_profile->cp_num_ports; i++) { 751 if (ksi->hki_perfcntr64[i].hki64_enabled) { 752 (void) hermon_kstat_perfcntr64_read(state, 753 i + 1, 1); 754 } 755 } 756 /* sleep for a second */ 757 (void) cv_reltimedwait(&ksi->hki_perfcntr64_cv, 758 &ksi->hki_perfcntr64_lock, delta, TR_CLOCK_TICK); 759 } 760 ksi->hki_perfcntr64_flags = 0; 761 mutex_exit(&ksi->hki_perfcntr64_lock); 762 } 763 764 /* 765 * hermon_kstat_perfcntr64_thread_create() 766 * Context: Called from the kstat context 767 * 768 * Create a thread that maintains 64 bit performance counters in software. 769 */ 770 static void 771 hermon_kstat_perfcntr64_thread_create(hermon_state_t *state) 772 { 773 hermon_ks_info_t *ksi = state->hs_ks_info; 774 kthread_t *thr; 775 776 ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock)); 777 778 /* 779 * One thread per hermon instance. Don't create a thread if already 780 * created. 781 */ 782 if (!(ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_CREATED)) { 783 thr = thread_create(NULL, 0, 784 hermon_kstat_perfcntr64_update_thread, 785 state, 0, &p0, TS_RUN, minclsyspri); 786 ksi->hki_perfcntr64_thread_id = thr->t_did; 787 ksi->hki_perfcntr64_flags |= HERMON_PERFCNTR64_THREAD_CREATED; 788 } 789 } 790 791 /* 792 * hermon_kstat_perfcntr64_thread_exit() 793 * Context: Called from attach, detach or kstat context 794 */ 795 static void 796 hermon_kstat_perfcntr64_thread_exit(hermon_ks_info_t *ksi) 797 { 798 kt_did_t tid; 799 800 ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock)); 801 802 if (ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_CREATED) { 803 /* 804 * Signal the thread to exit and wait until the thread exits. 805 */ 806 ksi->hki_perfcntr64_flags |= HERMON_PERFCNTR64_THREAD_EXIT; 807 tid = ksi->hki_perfcntr64_thread_id; 808 cv_signal(&ksi->hki_perfcntr64_cv); 809 810 mutex_exit(&ksi->hki_perfcntr64_lock); 811 thread_join(tid); 812 mutex_enter(&ksi->hki_perfcntr64_lock); 813 } 814 } 815 816 /* 817 * hermon_kstat_perfcntr64_update_ext() 818 * Context: Called from the kstat context 819 * 820 * Update perf_counters kstats with the values of the extended port counters 821 * from the hardware. 822 */ 823 static int 824 hermon_kstat_perfcntr64_update_ext(hermon_perfcntr64_ks_info_t *ksi64, int rw, 825 struct kstat_named *data) 826 { 827 hermon_hw_sm_extperfcntr_t sm_extperfcntr; 828 829 /* 830 * The "enable" component of the kstat is the only writable kstat. 831 * It is a no-op when the hardware supports extended port counters. 832 */ 833 if (rw == KSTAT_WRITE) 834 return (0); 835 836 /* 837 * Read the counters and update kstats. 838 */ 839 if (hermon_getextperfcntr_cmd_post(ksi64->hki64_state, 840 ksi64->hki64_port_num, HERMON_CMD_NOSLEEP_SPIN, &sm_extperfcntr) != 841 HERMON_CMD_SUCCESS) { 842 return (EIO); 843 } 844 845 data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 1; 846 847 data[HERMON_PERFCNTR64_XMIT_DATA_IDX].value.ui64 = 848 sm_extperfcntr.portxmdata; 849 850 data[HERMON_PERFCNTR64_RECV_DATA_IDX].value.ui64 = 851 sm_extperfcntr.portrcdata; 852 853 data[HERMON_PERFCNTR64_XMIT_PKTS_IDX].value.ui64 = 854 sm_extperfcntr.portxmpkts; 855 856 data[HERMON_PERFCNTR64_RECV_PKTS_IDX].value.ui64 = 857 sm_extperfcntr.portrcpkts; 858 859 return (0); 860 } 861 862 /* 863 * hermon_kstat_perfcntr64_update() 864 * Context: Called from the kstat context 865 * 866 * See the general comment on 64 bit kstats for performance counters: 867 */ 868 static int 869 hermon_kstat_perfcntr64_update(kstat_t *ksp, int rw) 870 { 871 hermon_state_t *state; 872 struct kstat_named *data; 873 hermon_ks_info_t *ksi; 874 hermon_perfcntr64_ks_info_t *ksi64; 875 int i, thr_exit; 876 int rv; 877 878 ksi64 = ksp->ks_private; 879 state = ksi64->hki64_state; 880 ksi = state->hs_ks_info; 881 data = (struct kstat_named *)(ksp->ks_data); 882 883 mutex_enter(&ksi->hki_perfcntr64_lock); 884 885 if (ksi64->hki64_ext_port_counters_supported) { 886 rv = hermon_kstat_perfcntr64_update_ext(ksi64, rw, data); 887 mutex_exit(&ksi->hki_perfcntr64_lock); 888 return (rv); 889 } 890 891 /* 892 * 64 bit performance counters maintained by the software is not 893 * enabled by default. Enable them upon a writing a non-zero value 894 * to "enable" kstat. Disable them upon a writing zero to the 895 * "enable" kstat. 896 */ 897 if (rw == KSTAT_WRITE) { 898 if (data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32) { 899 if (ksi64->hki64_enabled == 0) { 900 /* 901 * Reset the hardware counters to ensure that 902 * the hardware counter doesn't max out 903 * (and hence stop counting) before we get 904 * a chance to reset the counter in 905 * hermon_kstat_perfcntr64_update_thread. 906 */ 907 if (hermon_getperfcntr_cmd_post(state, 908 ksi64->hki64_port_num, 909 HERMON_CMD_NOSLEEP_SPIN, NULL, 1) != 910 HERMON_CMD_SUCCESS) { 911 mutex_exit(&ksi->hki_perfcntr64_lock); 912 return (EIO); 913 } 914 915 /* Enable 64 bit software counters */ 916 ksi64->hki64_enabled = 1; 917 for (i = 0; 918 i < HERMON_PERFCNTR64_NUM_COUNTERS; i++) { 919 ksi64->hki64_counters[i] = 0; 920 ksi64->hki64_last_read[i] = 0; 921 } 922 hermon_kstat_perfcntr64_thread_create(state); 923 } 924 925 } else if (ksi64->hki64_enabled) { 926 /* Disable 64 bit software counters */ 927 ksi64->hki64_enabled = 0; 928 thr_exit = 1; 929 for (i = 0; i < state->hs_cfg_profile->cp_num_ports; 930 i++) { 931 if (ksi->hki_perfcntr64[i].hki64_enabled) { 932 thr_exit = 0; 933 break; 934 } 935 } 936 if (thr_exit) 937 hermon_kstat_perfcntr64_thread_exit(ksi); 938 } 939 } else if (ksi64->hki64_enabled) { 940 /* 941 * Read the counters and update kstats. 942 */ 943 if (hermon_kstat_perfcntr64_read(state, ksi64->hki64_port_num, 944 0) != HERMON_CMD_SUCCESS) { 945 mutex_exit(&ksi->hki_perfcntr64_lock); 946 return (EIO); 947 } 948 949 data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 1; 950 951 data[HERMON_PERFCNTR64_XMIT_DATA_IDX].value.ui64 = 952 ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_DATA_IDX] + 953 ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX]; 954 955 data[HERMON_PERFCNTR64_RECV_DATA_IDX].value.ui64 = 956 ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_DATA_IDX] + 957 ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX]; 958 959 data[HERMON_PERFCNTR64_XMIT_PKTS_IDX].value.ui64 = 960 ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_PKTS_IDX] + 961 ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX]; 962 963 data[HERMON_PERFCNTR64_RECV_PKTS_IDX].value.ui64 = 964 ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_PKTS_IDX] + 965 ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX]; 966 967 } else { 968 /* return 0 in kstats if not enabled */ 969 data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 0; 970 for (i = 1; i < HERMON_PERFCNTR64_NUM_COUNTERS; i++) 971 data[i].value.ui64 = 0; 972 } 973 974 mutex_exit(&ksi->hki_perfcntr64_lock); 975 return (0); 976 }