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