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