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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
29 * Hermon IB Performance Statistics routines
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.
36 #include <sys/types.h>
39 #include <sys/sunddi.h>
40 #include <sys/modctl.h>
42 #include <sys/ib/adapters/hermon/hermon.h>
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
);
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
,
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
);
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.
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},
82 * Return the maximum of (x) and (y)
84 #define MAX(x, y) (((x) > (y)) ? (x) : (y))
87 * Set (x) to the maximum of (x) and (y)
89 #define SET_TO_MAX(x, y) \
97 * Context: Only called from attach() path context
100 hermon_kstat_init(hermon_state_t
*state
)
102 hermon_ks_info_t
*ksi
;
106 /* Allocate a kstat info structure */
107 ksi
= (hermon_ks_info_t
*)kmem_zalloc(sizeof (hermon_ks_info_t
),
110 return (DDI_FAILURE
);
112 state
->hs_ks_info
= ksi
;
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"
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
;
127 hermon_kstat_perfcntr64_create(state
, i
+ 1);
128 if (ksi
->hki_perfcntr64
[i
].hki64_ksp
== NULL
) {
129 goto kstat_init_fail
;
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
;
140 /* Initialize the control register and initial counter values */
146 * Initialize the Hermon hki_ib_perfcnt[] array values using the
147 * default values in hermon_ib_perfcnt_list[]
149 for (i
= 0; i
< HERMON_CNTR_NUMENTRIES
; i
++) {
150 ksi
->hki_ib_perfcnt
[i
] = hermon_ib_perfcnt_list
[i
];
153 mutex_init(&ksi
->hki_perfcntr64_lock
, NULL
, MUTEX_DRIVER
, NULL
);
154 cv_init(&ksi
->hki_perfcntr64_cv
, NULL
, CV_DRIVER
, NULL
);
156 return (DDI_SUCCESS
);
161 /* Delete all the previously created kstats */
162 if (ksi
->hki_cntr_ksp
!= NULL
) {
163 kstat_delete(ksi
->hki_cntr_ksp
);
165 for (i
= 0; i
< numports
; i
++) {
166 if (ksi
->hki_picN_ksp
[i
] != NULL
) {
167 kstat_delete(ksi
->hki_picN_ksp
[i
]);
169 if (ksi
->hki_perfcntr64
[i
].hki64_ksp
!= NULL
) {
170 kstat_delete(ksi
->hki_perfcntr64
[i
].hki64_ksp
);
174 /* Free the kstat info structure */
175 kmem_free(ksi
, sizeof (hermon_ks_info_t
));
177 return (DDI_FAILURE
);
182 * hermon_kstat_init()
183 * Context: Only called from attach() and/or detach() path contexts
186 hermon_kstat_fini(hermon_state_t
*state
)
188 hermon_ks_info_t
*ksi
;
192 /* Get pointer to kstat info */
193 ksi
= state
->hs_ks_info
;
196 * Signal the perfcntr64_update_thread to exit and wait until the
199 mutex_enter(&ksi
->hki_perfcntr64_lock
);
200 hermon_kstat_perfcntr64_thread_exit(ksi
);
201 mutex_exit(&ksi
->hki_perfcntr64_lock
);
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
]);
210 if (ksi
->hki_perfcntr64
[i
].hki64_ksp
!= NULL
) {
211 kstat_delete(ksi
->hki_perfcntr64
[i
].hki64_ksp
);
215 /* Delete the "counter" kstats (one per port) */
216 kstat_delete(ksi
->hki_cntr_ksp
);
218 cv_destroy(&ksi
->hki_perfcntr64_cv
);
219 mutex_destroy(&ksi
->hki_perfcntr64_lock
);
221 /* Free the kstat info structure */
222 kmem_free(ksi
, sizeof (hermon_ks_info_t
));
227 * hermon_kstat_picN_create()
228 * Context: Only called from attach() path context
231 hermon_kstat_picN_create(hermon_state_t
*state
, int num_pic
, int num_evt
,
232 hermon_ks_mask_t
*ev_array
)
235 struct kstat_named
*pic_named_data
;
241 * Create the "picN" kstat. In the steps, below we will attach
242 * all of our named event types to it.
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
, 0);
249 if (picN_ksp
== NULL
) {
252 pic_named_data
= (struct kstat_named
*)(picN_ksp
->ks_data
);
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).
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
,
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
,
272 /* Install the kstat */
273 kstat_install(picN_ksp
);
280 * hermon_kstat_cntr_create()
281 * Context: Only called from attach() path context
284 hermon_kstat_cntr_create(hermon_state_t
*state
, int num_pic
,
285 int (*update
)(kstat_t
*, int))
287 struct kstat
*cntr_ksp
;
288 struct kstat_named
*cntr_named_data
;
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".
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
) {
305 cntr_named_data
= (struct kstat_named
*)(cntr_ksp
->ks_data
);
308 * Initialize the named kstats (for the "pcr" and for the
309 * individual "pic" kstats)
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
,
319 * Store the Hermon softstate pointer in the kstat's private field so
320 * that it is available to the update function.
322 cntr_ksp
->ks_private
= (void *)state
;
323 cntr_ksp
->ks_update
= update
;
325 /* Install the kstat */
326 kstat_install(cntr_ksp
);
333 * hermon_kstat_cntr_update()
334 * Context: Called from the kstat context
337 hermon_kstat_cntr_update(kstat_t
*ksp
, int rw
)
339 hermon_state_t
*state
;
340 hermon_ks_mask_t
*ib_perf
;
341 hermon_ks_info_t
*ksi
;
342 struct kstat_named
*data
;
346 uint_t numports
, indx
;
348 hermon_hw_sm_perfcntr_t sm_perfcntr
;
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.
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
))
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.
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.
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.
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
;
386 * Get the current "pcr" value and extract the lower
387 * portion (corresponding to the counters for "pic0")
390 indx
= pcr
& HERMON_CNTR_MASK
;
391 data
[0].value
.ui64
= pcr
;
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.
401 oldval
= ib_perf
[indx
].ks_old_pic0
;
403 status
= hermon_getperfcntr_cmd_post(state
, 1,
404 HERMON_CMD_NOSLEEP_SPIN
, &sm_perfcntr
, 0);
405 if (status
!= HERMON_CMD_SUCCESS
) {
409 case 0: /* port_xmit_data */
410 tmp
= sm_perfcntr
.portxmdata
;
412 case 1: /* port_recv_data */
413 tmp
= sm_perfcntr
.portrcdata
;
415 case 2: /* port_xmit_pkts */
416 tmp
= sm_perfcntr
.portxmpkts
;
418 case 3: /* port_recv_pkts */
419 tmp
= sm_perfcntr
.portrcpkts
;
421 case 4: /* port_recv_err */
422 tmp
= sm_perfcntr
.portrcv
;
424 case 5: /* port_xmit_discards */
425 tmp
= sm_perfcntr
.portxmdiscard
;
427 case 6: /* vl15_dropped */
428 tmp
= sm_perfcntr
.vl15drop
;
430 case 7: /* port_xmit_wait */
431 tmp
= sm_perfcntr
.portxmwait
;
433 case 8: /* port_recv_remote_phys_err */
434 tmp
= sm_perfcntr
.portrcvrem
;
436 case 9: /* port_xmit_constraint_err */
437 tmp
= sm_perfcntr
.portxmconstr
;
439 case 10: /* port_recv_constraint_err */
440 tmp
= sm_perfcntr
.portrcconstr
;
442 case 11: /* symbol_err_counter */
443 tmp
= sm_perfcntr
.symerr
;
445 case 12: /* link_err_recovery_cnt */
446 tmp
= sm_perfcntr
.linkerrrec
;
448 case 13: /* link_downed_cnt */
449 tmp
= sm_perfcntr
.linkdown
;
451 case 14: /* excessive_buffer_overruns */
452 tmp
= sm_perfcntr
.xsbuffovrun
;
454 case 15: /* local_link_integrity_err */
455 tmp
= sm_perfcntr
.locallinkint
;
457 case 16: /* clear_pic */
461 cmn_err(CE_CONT
, "perf counter out of range\n");
464 ib_perf
[indx
].ks_old_pic0
= tmp
;
467 ksi
->hki_pic0
+= tmp
;
468 data
[1].value
.ui64
= ksi
->hki_pic0
;
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")
475 if (numports
== HERMON_MAX_PORTS
) {
476 indx
= pcr
>> HERMON_CNTR_SIZE
;
477 oldval
= ib_perf
[indx
].ks_old_pic1
;
479 status
= hermon_getperfcntr_cmd_post(state
, 2,
480 HERMON_CMD_NOSLEEP_SPIN
, &sm_perfcntr
, 0);
481 if (status
!= HERMON_CMD_SUCCESS
) {
485 case 0: /* port_xmit_data */
486 tmp
= sm_perfcntr
.portxmdata
;
488 case 1: /* port_recv_data */
489 tmp
= sm_perfcntr
.portrcdata
;
491 case 2: /* port_xmit_pkts */
492 tmp
= sm_perfcntr
.portxmpkts
;
494 case 3: /* port_recv_pkts */
495 tmp
= sm_perfcntr
.portrcpkts
;
497 case 4: /* port_recv_err */
498 tmp
= sm_perfcntr
.portrcv
;
500 case 5: /* port_xmit_discards */
501 tmp
= sm_perfcntr
.portxmdiscard
;
503 case 6: /* vl15_dropped */
504 tmp
= sm_perfcntr
.vl15drop
;
506 case 7: /* port_xmit_wait */
507 tmp
= sm_perfcntr
.portxmwait
;
509 case 8: /* port_recv_remote_phys_err */
510 tmp
= sm_perfcntr
.portrcvrem
;
512 case 9: /* port_xmit_constraint_err */
513 tmp
= sm_perfcntr
.portxmconstr
;
515 case 10: /* port_recv_constraint_err */
516 tmp
= sm_perfcntr
.portrcconstr
;
518 case 11: /* symbol_err_counter */
519 tmp
= sm_perfcntr
.symerr
;
521 case 12: /* link_err_recovery_cnt */
522 tmp
= sm_perfcntr
.linkerrrec
;
524 case 13: /* link_downed_cnt */
525 tmp
= sm_perfcntr
.linkdown
;
527 case 14: /* excessive_buffer_overruns */
528 tmp
= sm_perfcntr
.xsbuffovrun
;
530 case 15: /* local_link_integrity_err */
531 tmp
= sm_perfcntr
.locallinkint
;
533 case 16: /* clear_pic */
537 cmn_err(CE_CONT
, "perf counter out of range\n");
540 ib_perf
[indx
].ks_old_pic1
= tmp
;
543 ksi
->hki_pic1
+= tmp
;
544 data
[2].value
.ui64
= ksi
->hki_pic1
;
552 * 64 bit kstats for performance counters:
554 * Export 64 bit performance counters in kstats.
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.
561 * The software based counters are maintained as follows:
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
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.
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.
588 * hermon_kstat_perfcntr64_create()
589 * Context: Only called from attach() path context
591 * Create "port#/perf_counters" kstat for the specified port number.
594 hermon_kstat_perfcntr64_create(hermon_state_t
*state
, uint_t port_num
)
596 hermon_ks_info_t
*ksi
= state
->hs_ks_info
;
597 struct kstat
*cntr_ksp
;
598 struct kstat_named
*cntr_named_data
;
602 int status
, ext_width_supported
;
604 ASSERT(port_num
!= 0);
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
;
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",
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
) {
623 cntr_named_data
= (struct kstat_named
*)(cntr_ksp
->ks_data
);
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
);
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
;
640 cntr_ksp
->ks_private
= &ksi
->hki_perfcntr64
[port_num
- 1];
641 cntr_ksp
->ks_update
= hermon_kstat_perfcntr64_update
;
643 /* Install the kstat */
644 kstat_install(cntr_ksp
);
648 * hermon_kstat_perfcntr64_read()
650 * Read the values of 32 bit hardware counters.
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.
655 * If reset is false, just save the values read from the 32 bit hardware
656 * counters in hki64_last_read[].
658 * See the general comment on the 64 bit performance counters
659 * regarding the use of last read 32 bit hardware counter values.
662 hermon_kstat_perfcntr64_read(hermon_state_t
*state
, uint_t port
, int reset
)
664 hermon_ks_info_t
*ksi
= state
->hs_ks_info
;
665 hermon_perfcntr64_ks_info_t
*ksi64
= &ksi
->hki_perfcntr64
[port
- 1];
668 hermon_hw_sm_perfcntr_t sm_perfcntr
;
670 ASSERT(MUTEX_HELD(&ksi
->hki_perfcntr64_lock
));
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
) {
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
) {
689 * Update 64 bit software counters
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
;
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
;
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
;
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
;
707 for (i
= 0; i
< HERMON_PERFCNTR64_NUM_COUNTERS
; i
++)
708 ksi64
->hki64_last_read
[i
] = 0;
712 * Update ksi64->hki64_last_read[]
715 ksi64
->hki64_last_read
[HERMON_PERFCNTR64_XMIT_DATA_IDX
],
716 sm_perfcntr
.portxmdata
);
719 ksi64
->hki64_last_read
[HERMON_PERFCNTR64_RECV_DATA_IDX
],
720 sm_perfcntr
.portrcdata
);
723 ksi64
->hki64_last_read
[HERMON_PERFCNTR64_XMIT_PKTS_IDX
],
724 sm_perfcntr
.portxmpkts
);
727 ksi64
->hki64_last_read
[HERMON_PERFCNTR64_RECV_PKTS_IDX
],
728 sm_perfcntr
.portrcpkts
);
731 return (HERMON_CMD_SUCCESS
);
735 * hermon_kstat_perfcntr64_update_thread()
736 * Context: Entry point for a kernel thread
738 * Maintain 64 bit performance counters in software using the 32 bit
742 hermon_kstat_perfcntr64_update_thread(void *arg
)
744 hermon_state_t
*state
= (hermon_state_t
*)arg
;
745 hermon_ks_info_t
*ksi
= state
->hs_ks_info
;
747 clock_t delta
= drv_usectohz(1000000);
749 mutex_enter(&ksi
->hki_perfcntr64_lock
);
751 * Every one second update the values 64 bit software counters
752 * for all ports. Exit if HERMON_PERFCNTR64_THREAD_EXIT flag is set.
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
,
761 /* sleep for a second */
762 (void) cv_reltimedwait(&ksi
->hki_perfcntr64_cv
,
763 &ksi
->hki_perfcntr64_lock
, delta
, TR_CLOCK_TICK
);
765 ksi
->hki_perfcntr64_flags
= 0;
766 mutex_exit(&ksi
->hki_perfcntr64_lock
);
770 * hermon_kstat_perfcntr64_thread_create()
771 * Context: Called from the kstat context
773 * Create a thread that maintains 64 bit performance counters in software.
776 hermon_kstat_perfcntr64_thread_create(hermon_state_t
*state
)
778 hermon_ks_info_t
*ksi
= state
->hs_ks_info
;
781 ASSERT(MUTEX_HELD(&ksi
->hki_perfcntr64_lock
));
784 * One thread per hermon instance. Don't create a thread if already
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
;
797 * hermon_kstat_perfcntr64_thread_exit()
798 * Context: Called from attach, detach or kstat context
801 hermon_kstat_perfcntr64_thread_exit(hermon_ks_info_t
*ksi
)
805 ASSERT(MUTEX_HELD(&ksi
->hki_perfcntr64_lock
));
807 if (ksi
->hki_perfcntr64_flags
& HERMON_PERFCNTR64_THREAD_CREATED
) {
809 * Signal the thread to exit and wait until the thread exits.
811 ksi
->hki_perfcntr64_flags
|= HERMON_PERFCNTR64_THREAD_EXIT
;
812 tid
= ksi
->hki_perfcntr64_thread_id
;
813 cv_signal(&ksi
->hki_perfcntr64_cv
);
815 mutex_exit(&ksi
->hki_perfcntr64_lock
);
817 mutex_enter(&ksi
->hki_perfcntr64_lock
);
822 * hermon_kstat_perfcntr64_update_ext()
823 * Context: Called from the kstat context
825 * Update perf_counters kstats with the values of the extended port counters
829 hermon_kstat_perfcntr64_update_ext(hermon_perfcntr64_ks_info_t
*ksi64
, int rw
,
830 struct kstat_named
*data
)
832 hermon_hw_sm_extperfcntr_t sm_extperfcntr
;
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.
838 if (rw
== KSTAT_WRITE
)
842 * Read the counters and update kstats.
844 if (hermon_getextperfcntr_cmd_post(ksi64
->hki64_state
,
845 ksi64
->hki64_port_num
, HERMON_CMD_NOSLEEP_SPIN
, &sm_extperfcntr
) !=
846 HERMON_CMD_SUCCESS
) {
850 data
[HERMON_PERFCNTR64_ENABLE_IDX
].value
.ui32
= 1;
852 data
[HERMON_PERFCNTR64_XMIT_DATA_IDX
].value
.ui64
=
853 sm_extperfcntr
.portxmdata
;
855 data
[HERMON_PERFCNTR64_RECV_DATA_IDX
].value
.ui64
=
856 sm_extperfcntr
.portrcdata
;
858 data
[HERMON_PERFCNTR64_XMIT_PKTS_IDX
].value
.ui64
=
859 sm_extperfcntr
.portxmpkts
;
861 data
[HERMON_PERFCNTR64_RECV_PKTS_IDX
].value
.ui64
=
862 sm_extperfcntr
.portrcpkts
;
868 * hermon_kstat_perfcntr64_update()
869 * Context: Called from the kstat context
871 * See the general comment on 64 bit kstats for performance counters:
874 hermon_kstat_perfcntr64_update(kstat_t
*ksp
, int rw
)
876 hermon_state_t
*state
;
877 struct kstat_named
*data
;
878 hermon_ks_info_t
*ksi
;
879 hermon_perfcntr64_ks_info_t
*ksi64
;
883 ksi64
= ksp
->ks_private
;
884 state
= ksi64
->hki64_state
;
885 ksi
= state
->hs_ks_info
;
886 data
= (struct kstat_named
*)(ksp
->ks_data
);
888 mutex_enter(&ksi
->hki_perfcntr64_lock
);
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
);
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
902 if (rw
== KSTAT_WRITE
) {
903 if (data
[HERMON_PERFCNTR64_ENABLE_IDX
].value
.ui32
) {
904 if (ksi64
->hki64_enabled
== 0) {
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.
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
);
920 /* Enable 64 bit software counters */
921 ksi64
->hki64_enabled
= 1;
923 i
< HERMON_PERFCNTR64_NUM_COUNTERS
; i
++) {
924 ksi64
->hki64_counters
[i
] = 0;
925 ksi64
->hki64_last_read
[i
] = 0;
927 hermon_kstat_perfcntr64_thread_create(state
);
930 } else if (ksi64
->hki64_enabled
) {
931 /* Disable 64 bit software counters */
932 ksi64
->hki64_enabled
= 0;
934 for (i
= 0; i
< state
->hs_cfg_profile
->cp_num_ports
;
936 if (ksi
->hki_perfcntr64
[i
].hki64_enabled
) {
942 hermon_kstat_perfcntr64_thread_exit(ksi
);
944 } else if (ksi64
->hki64_enabled
) {
946 * Read the counters and update kstats.
948 if (hermon_kstat_perfcntr64_read(state
, ksi64
->hki64_port_num
,
949 0) != HERMON_CMD_SUCCESS
) {
950 mutex_exit(&ksi
->hki_perfcntr64_lock
);
954 data
[HERMON_PERFCNTR64_ENABLE_IDX
].value
.ui32
= 1;
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
];
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
];
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
];
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
];
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;
979 mutex_exit(&ksi
->hki_perfcntr64_lock
);