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