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 }