xref: /illumos-gate/usr/src/uts/common/io/ib/adapters/hermon/hermon_stats.c (revision d1a5c8385583011b8adaf259d3460c22595b4a66)
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.  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  * Since the hardware as of now does not support 64 bit performance counters,
555  * we maintain 64 bit performance counters in software using the 32 bit
556  * hardware counters.
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  *
570  * If performance monitor is enabled in subnet manager, the SM could
571  * periodically reset the hardware counters by sending perf-MADs. So only
572  * one of either our software 64 bit counters or the SM performance monitor
573  * could be enabled at the same time. However, if both of them are enabled at
574  * the same time we still do our best by keeping track of the values of the
575  * last read 32 bit hardware counters. If the current read of a 32 bit hardware
576  * counter is less than the last read of the counter, we ignore the current
577  * value and go with the last read value.
578  */
579 
580 /*
581  * hermon_kstat_perfcntr64_create()
582  *    Context: Only called from attach() path context
583  *
584  * Create "port#/perf_counters" kstat for the specified port number.
585  */
586 void
587 hermon_kstat_perfcntr64_create(hermon_state_t *state, uint_t port_num)
588 {
589 	hermon_ks_info_t	*ksi = state->hs_ks_info;
590 	struct kstat		*cntr_ksp;
591 	struct kstat_named	*cntr_named_data;
592 	int			drv_instance;
593 	char			*drv_name;
594 	char			kname[32];
595 
596 	ASSERT(port_num != 0);
597 
598 	drv_name = (char *)ddi_driver_name(state->hs_dip);
599 	drv_instance = ddi_get_instance(state->hs_dip);
600 	(void) snprintf(kname, sizeof (kname), "port%u/perf_counters",
601 	    port_num);
602 	cntr_ksp = kstat_create(drv_name, drv_instance, kname, "ib",
603 	    KSTAT_TYPE_NAMED, HERMON_PERFCNTR64_NUM_COUNTERS,
604 	    KSTAT_FLAG_WRITABLE);
605 	if (cntr_ksp == NULL) {
606 		return;
607 	}
608 	cntr_named_data = (struct kstat_named *)(cntr_ksp->ks_data);
609 
610 	kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_ENABLE_IDX],
611 	    "enable", KSTAT_DATA_UINT32);
612 	kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_XMIT_DATA_IDX],
613 	    "xmit_data", KSTAT_DATA_UINT64);
614 	kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_RECV_DATA_IDX],
615 	    "recv_data", KSTAT_DATA_UINT64);
616 	kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_XMIT_PKTS_IDX],
617 	    "xmit_pkts", KSTAT_DATA_UINT64);
618 	kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_RECV_PKTS_IDX],
619 	    "recv_pkts", KSTAT_DATA_UINT64);
620 
621 	ksi->hki_perfcntr64[port_num - 1].hki64_ksp = cntr_ksp;
622 	ksi->hki_perfcntr64[port_num - 1].hki64_port_num = port_num;
623 	ksi->hki_perfcntr64[port_num - 1].hki64_state = state;
624 
625 	cntr_ksp->ks_private = &ksi->hki_perfcntr64[port_num - 1];
626 	cntr_ksp->ks_update  = hermon_kstat_perfcntr64_update;
627 
628 	/* Install the kstat */
629 	kstat_install(cntr_ksp);
630 }
631 
632 /*
633  * hermon_kstat_perfcntr64_read()
634  *
635  * Read the values of 32 bit hardware counters.
636  *
637  * If reset is true, reset the 32 bit hardware counters. Add the values of the
638  * 32 bit hardware counters to the 64 bit software counters.
639  *
640  * If reset is false, just save the values read from the 32 bit hardware
641  * counters in hki64_last_read[].
642  *
643  * See the general comment on the 64 bit performance counters
644  * regarding the use of last read 32 bit hardware counter values.
645  */
646 static int
647 hermon_kstat_perfcntr64_read(hermon_state_t *state, uint_t port, int reset)
648 {
649 	hermon_ks_info_t	*ksi = state->hs_ks_info;
650 	hermon_perfcntr64_ks_info_t *ksi64 = &ksi->hki_perfcntr64[port - 1];
651 	int			status, i;
652 	uint32_t		tmp;
653 	hermon_hw_sm_perfcntr_t	sm_perfcntr;
654 
655 	ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock));
656 	ASSERT(port != 0);
657 
658 	/* read the 32 bit hardware counters */
659 	status = hermon_getperfcntr_cmd_post(state, port,
660 	    HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
661 	if (status != HERMON_CMD_SUCCESS) {
662 		return (status);
663 	}
664 
665 	if (reset) {
666 		/* reset the hardware counters */
667 		status = hermon_getperfcntr_cmd_post(state, port,
668 		    HERMON_CMD_NOSLEEP_SPIN, NULL, 1);
669 		if (status != HERMON_CMD_SUCCESS) {
670 			return (status);
671 		}
672 
673 		/*
674 		 * Update 64 bit software counters
675 		 */
676 		tmp = MAX(sm_perfcntr.portxmdata,
677 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX]);
678 		ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_DATA_IDX] += tmp;
679 
680 		tmp = MAX(sm_perfcntr.portrcdata,
681 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX]);
682 		ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_DATA_IDX] += tmp;
683 
684 		tmp = MAX(sm_perfcntr.portxmpkts,
685 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX]);
686 		ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_PKTS_IDX] += tmp;
687 
688 		tmp = MAX(sm_perfcntr.portrcpkts,
689 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX]);
690 		ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_PKTS_IDX] += tmp;
691 
692 		for (i = 0; i < HERMON_PERFCNTR64_NUM_COUNTERS; i++)
693 			ksi64->hki64_last_read[i] = 0;
694 
695 	} else {
696 		/*
697 		 * Update ksi64->hki64_last_read[]
698 		 */
699 		SET_TO_MAX(
700 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX],
701 		    sm_perfcntr.portxmdata);
702 
703 		SET_TO_MAX(
704 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX],
705 		    sm_perfcntr.portrcdata);
706 
707 		SET_TO_MAX(
708 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX],
709 		    sm_perfcntr.portxmpkts);
710 
711 		SET_TO_MAX(
712 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX],
713 		    sm_perfcntr.portrcpkts);
714 	}
715 
716 	return (HERMON_CMD_SUCCESS);
717 }
718 
719 /*
720  * hermon_kstat_perfcntr64_update_thread()
721  *    Context: Entry point for a kernel thread
722  *
723  * Maintain 64 bit performance counters in software using the 32 bit
724  * hardware counters.
725  */
726 static void
727 hermon_kstat_perfcntr64_update_thread(void *arg)
728 {
729 	hermon_state_t		*state = (hermon_state_t *)arg;
730 	hermon_ks_info_t	*ksi = state->hs_ks_info;
731 	uint_t			i;
732 
733 	mutex_enter(&ksi->hki_perfcntr64_lock);
734 	/*
735 	 * Every one second update the values 64 bit software counters
736 	 * for all ports. Exit if HERMON_PERFCNTR64_THREAD_EXIT flag is set.
737 	 */
738 	while (!(ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_EXIT)) {
739 		for (i = 0; i < state->hs_cfg_profile->cp_num_ports; i++) {
740 			if (ksi->hki_perfcntr64[i].hki64_enabled) {
741 				(void) hermon_kstat_perfcntr64_read(state,
742 				    i + 1, 1);
743 			}
744 		}
745 		/* sleep for a second */
746 		(void) cv_timedwait(&ksi->hki_perfcntr64_cv,
747 		    &ksi->hki_perfcntr64_lock,
748 		    ddi_get_lbolt() + drv_usectohz(1000000));
749 	}
750 	ksi->hki_perfcntr64_flags = 0;
751 	mutex_exit(&ksi->hki_perfcntr64_lock);
752 }
753 
754 /*
755  * hermon_kstat_perfcntr64_thread_create()
756  *    Context: Called from the kstat context
757  *
758  * Create a thread that maintains 64 bit performance counters in software.
759  */
760 static void
761 hermon_kstat_perfcntr64_thread_create(hermon_state_t *state)
762 {
763 	hermon_ks_info_t	*ksi = state->hs_ks_info;
764 	kthread_t		*thr;
765 
766 	ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock));
767 
768 	/*
769 	 * One thread per hermon instance. Don't create a thread if already
770 	 * created.
771 	 */
772 	if (!(ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_CREATED)) {
773 		thr = thread_create(NULL, 0,
774 		    hermon_kstat_perfcntr64_update_thread,
775 		    state, 0, &p0, TS_RUN, minclsyspri);
776 		ksi->hki_perfcntr64_thread_id = thr->t_did;
777 		ksi->hki_perfcntr64_flags |= HERMON_PERFCNTR64_THREAD_CREATED;
778 	}
779 }
780 
781 /*
782  * hermon_kstat_perfcntr64_thread_exit()
783  *    Context: Called from attach, detach or kstat context
784  */
785 static void
786 hermon_kstat_perfcntr64_thread_exit(hermon_ks_info_t *ksi)
787 {
788 	kt_did_t	tid;
789 
790 	ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock));
791 
792 	if (ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_CREATED) {
793 		/*
794 		 * Signal the thread to exit and wait until the thread exits.
795 		 */
796 		ksi->hki_perfcntr64_flags |= HERMON_PERFCNTR64_THREAD_EXIT;
797 		tid = ksi->hki_perfcntr64_thread_id;
798 		cv_signal(&ksi->hki_perfcntr64_cv);
799 
800 		mutex_exit(&ksi->hki_perfcntr64_lock);
801 		thread_join(tid);
802 		mutex_enter(&ksi->hki_perfcntr64_lock);
803 	}
804 }
805 
806 /*
807  * hermon_kstat_perfcntr64_update()
808  *    Context: Called from the kstat context
809  *
810  * See the general comment on 64 bit kstats for performance counters:
811  */
812 static int
813 hermon_kstat_perfcntr64_update(kstat_t *ksp, int rw)
814 {
815 	hermon_state_t			*state;
816 	struct kstat_named		*data;
817 	hermon_ks_info_t		*ksi;
818 	hermon_perfcntr64_ks_info_t	*ksi64;
819 	int				i, thr_exit;
820 
821 	ksi64	= ksp->ks_private;
822 	state	= ksi64->hki64_state;
823 	ksi	= state->hs_ks_info;
824 	data	= (struct kstat_named *)(ksp->ks_data);
825 
826 	mutex_enter(&ksi->hki_perfcntr64_lock);
827 
828 	/*
829 	 * 64 bit performance counters maintained by the software is not
830 	 * enabled by default. Enable them upon a writing a non-zero value
831 	 * to "enable" kstat. Disable them upon a writing zero to the
832 	 * "enable" kstat.
833 	 */
834 	if (rw == KSTAT_WRITE) {
835 		if (data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32) {
836 			if (ksi64->hki64_enabled == 0) {
837 				/* Enable 64 bit software counters */
838 				ksi64->hki64_enabled = 1;
839 				for (i = 0;
840 				    i < HERMON_PERFCNTR64_NUM_COUNTERS; i++) {
841 					ksi64->hki64_counters[i] = 0;
842 					ksi64->hki64_last_read[i] = 0;
843 				}
844 				hermon_kstat_perfcntr64_thread_create(state);
845 			}
846 
847 		} else if (ksi64->hki64_enabled) {
848 			/* Disable 64 bit software counters */
849 			ksi64->hki64_enabled = 0;
850 			thr_exit = 1;
851 			for (i = 0; i < state->hs_cfg_profile->cp_num_ports;
852 			    i++) {
853 				if (ksi->hki_perfcntr64[i].hki64_enabled) {
854 					thr_exit = 0;
855 					break;
856 				}
857 			}
858 			if (thr_exit)
859 				hermon_kstat_perfcntr64_thread_exit(ksi);
860 		}
861 	} else if (ksi64->hki64_enabled) {
862 		/*
863 		 * Read the counters and update kstats.
864 		 */
865 		if (hermon_kstat_perfcntr64_read(state, ksi64->hki64_port_num,
866 		    0) != HERMON_CMD_SUCCESS) {
867 			mutex_exit(&ksi->hki_perfcntr64_lock);
868 			return (EIO);
869 		}
870 
871 		data[HERMON_PERFCNTR64_XMIT_DATA_IDX].value.ui64 =
872 		    ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_DATA_IDX] +
873 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX];
874 
875 		data[HERMON_PERFCNTR64_RECV_DATA_IDX].value.ui64 =
876 		    ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_DATA_IDX] +
877 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX];
878 
879 		data[HERMON_PERFCNTR64_XMIT_PKTS_IDX].value.ui64 =
880 		    ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_PKTS_IDX] +
881 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX];
882 
883 		data[HERMON_PERFCNTR64_RECV_PKTS_IDX].value.ui64 =
884 		    ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_PKTS_IDX] +
885 		    ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX];
886 
887 	} else {
888 		/* return 0 in kstats if not enabled */
889 		data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 0;
890 		for (i = 1; i < HERMON_PERFCNTR64_NUM_COUNTERS; i++)
891 			data[i].value.ui64 = 0;
892 	}
893 
894 	mutex_exit(&ksi->hki_perfcntr64_lock);
895 	return (0);
896 }
897