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