Print this page
8368 remove warlock leftovers from usr/src/uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/ib/adapters/hermon/hermon_stats.c
+++ new/usr/src/uts/common/io/ib/adapters/hermon/hermon_stats.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * hermon_stats.c
29 29 * Hermon IB Performance Statistics routines
30 30 *
31 31 * Implements all the routines necessary for setting up, querying, and
32 32 * (later) tearing down all the kstats necessary for implementing to
33 33 * the interfaces necessary to provide busstat(1M) access.
34 34 */
35 35
36 36 #include <sys/types.h>
37 37 #include <sys/conf.h>
38 38 #include <sys/ddi.h>
39 39 #include <sys/sunddi.h>
40 40 #include <sys/modctl.h>
41 41
42 42 #include <sys/ib/adapters/hermon/hermon.h>
43 43
44 44 static kstat_t *hermon_kstat_picN_create(hermon_state_t *state, int num_pic,
45 45 int num_evt, hermon_ks_mask_t *ev_array);
46 46 static kstat_t *hermon_kstat_cntr_create(hermon_state_t *state, int num_pic,
47 47 int (*update)(kstat_t *, int));
48 48 static int hermon_kstat_cntr_update(kstat_t *ksp, int rw);
49 49
50 50 void hermon_kstat_perfcntr64_create(hermon_state_t *state, uint_t port_num);
51 51 static int hermon_kstat_perfcntr64_read(hermon_state_t *state, uint_t port,
52 52 int reset);
53 53 static void hermon_kstat_perfcntr64_thread_exit(hermon_ks_info_t *ksi);
54 54 static int hermon_kstat_perfcntr64_update(kstat_t *ksp, int rw);
55 55
56 56 /*
57 57 * Hermon IB Performance Events structure
58 58 * This structure is read-only and is used to setup the individual kstats
59 59 * and to initialize the tki_ib_perfcnt[] array for each Hermon instance.
60 60 */
61 61 hermon_ks_mask_t hermon_ib_perfcnt_list[HERMON_CNTR_NUMENTRIES] = {
62 62 {"port_xmit_data", 0, 0},
63 63 {"port_recv_data", 0, 0},
64 64 {"port_xmit_pkts", 0, 0},
65 65 {"port_recv_pkts", 0, 0},
66 66 {"port_recv_err", 0, 0},
67 67 {"port_xmit_discards", 0, 0},
68 68 {"vl15_dropped", 0, 0},
69 69 {"port_xmit_wait", 0, 0},
70 70 {"port_recv_remote_phys_err", 0, 0},
71 71 {"port_xmit_constraint_err", 0, 0},
72 72 {"port_recv_constraint_err", 0, 0},
73 73 {"symbol_err_counter", 0, 0},
74 74 {"link_err_recovery_cnt", 0, 0},
75 75 {"link_downed_cnt", 0, 0},
76 76 {"excessive_buffer_overruns", 0, 0},
77 77 {"local_link_integrity_err", 0, 0},
78 78 {"clear_pic", 0, 0}
79 79 };
80 80
81 81 /*
82 82 * Return the maximum of (x) and (y)
83 83 */
84 84 #define MAX(x, y) (((x) > (y)) ? (x) : (y))
85 85
86 86 /*
87 87 * Set (x) to the maximum of (x) and (y)
88 88 */
89 89 #define SET_TO_MAX(x, y) \
90 90 { \
91 91 if ((x) < (y)) \
92 92 (x) = (y); \
93 93 }
94 94
95 95 /*
96 96 * hermon_kstat_init()
97 97 * Context: Only called from attach() path context
98 98 */
99 99 int
100 100 hermon_kstat_init(hermon_state_t *state)
101 101 {
102 102 hermon_ks_info_t *ksi;
103 103 uint_t numports;
104 104 int i;
105 105
106 106 /* Allocate a kstat info structure */
107 107 ksi = (hermon_ks_info_t *)kmem_zalloc(sizeof (hermon_ks_info_t),
108 108 KM_SLEEP);
109 109 if (ksi == NULL) {
110 110 return (DDI_FAILURE);
111 111 }
112 112 state->hs_ks_info = ksi;
113 113
114 114 /*
115 115 * Create as many "pic" and perfcntr64 kstats as we have IB ports.
116 116 * Enable all of the events specified in the "hermon_ib_perfcnt_list"
117 117 * structure.
118 118 */
119 119 numports = state->hs_cfg_profile->cp_num_ports;
120 120 for (i = 0; i < numports; i++) {
121 121 ksi->hki_picN_ksp[i] = hermon_kstat_picN_create(state, i,
122 122 HERMON_CNTR_NUMENTRIES, hermon_ib_perfcnt_list);
123 123 if (ksi->hki_picN_ksp[i] == NULL) {
124 124 goto kstat_init_fail;
125 125 }
126 126
127 127 hermon_kstat_perfcntr64_create(state, i + 1);
128 128 if (ksi->hki_perfcntr64[i].hki64_ksp == NULL) {
129 129 goto kstat_init_fail;
130 130 }
131 131 }
132 132
133 133 /* Create the "counters" kstat too */
134 134 ksi->hki_cntr_ksp = hermon_kstat_cntr_create(state, numports,
135 135 hermon_kstat_cntr_update);
136 136 if (ksi->hki_cntr_ksp == NULL) {
137 137 goto kstat_init_fail;
138 138 }
139 139
140 140 /* Initialize the control register and initial counter values */
141 141 ksi->hki_pcr = 0;
142 142 ksi->hki_pic0 = 0;
143 143 ksi->hki_pic1 = 0;
144 144
145 145 /*
146 146 * Initialize the Hermon hki_ib_perfcnt[] array values using the
147 147 * default values in hermon_ib_perfcnt_list[]
148 148 */
149 149 for (i = 0; i < HERMON_CNTR_NUMENTRIES; i++) {
150 150 ksi->hki_ib_perfcnt[i] = hermon_ib_perfcnt_list[i];
151 151 }
152 152
153 153 mutex_init(&ksi->hki_perfcntr64_lock, NULL, MUTEX_DRIVER, NULL);
154 154 cv_init(&ksi->hki_perfcntr64_cv, NULL, CV_DRIVER, NULL);
155 155
156 156 return (DDI_SUCCESS);
157 157
158 158
159 159 kstat_init_fail:
160 160
161 161 /* Delete all the previously created kstats */
162 162 if (ksi->hki_cntr_ksp != NULL) {
163 163 kstat_delete(ksi->hki_cntr_ksp);
164 164 }
165 165 for (i = 0; i < numports; i++) {
166 166 if (ksi->hki_picN_ksp[i] != NULL) {
167 167 kstat_delete(ksi->hki_picN_ksp[i]);
168 168 }
169 169 if (ksi->hki_perfcntr64[i].hki64_ksp != NULL) {
170 170 kstat_delete(ksi->hki_perfcntr64[i].hki64_ksp);
171 171 }
172 172 }
173 173
174 174 /* Free the kstat info structure */
175 175 kmem_free(ksi, sizeof (hermon_ks_info_t));
176 176
177 177 return (DDI_FAILURE);
178 178 }
179 179
180 180
181 181 /*
182 182 * hermon_kstat_init()
183 183 * Context: Only called from attach() and/or detach() path contexts
184 184 */
185 185 void
186 186 hermon_kstat_fini(hermon_state_t *state)
187 187 {
188 188 hermon_ks_info_t *ksi;
189 189 uint_t numports;
190 190 int i;
191 191
192 192 /* Get pointer to kstat info */
193 193 ksi = state->hs_ks_info;
194 194
195 195 /*
196 196 * Signal the perfcntr64_update_thread to exit and wait until the
197 197 * thread exits.
198 198 */
199 199 mutex_enter(&ksi->hki_perfcntr64_lock);
200 200 hermon_kstat_perfcntr64_thread_exit(ksi);
201 201 mutex_exit(&ksi->hki_perfcntr64_lock);
202 202
203 203 /* Delete all the "pic" and perfcntr64 kstats (one per port) */
204 204 numports = state->hs_cfg_profile->cp_num_ports;
205 205 for (i = 0; i < numports; i++) {
206 206 if (ksi->hki_picN_ksp[i] != NULL) {
207 207 kstat_delete(ksi->hki_picN_ksp[i]);
208 208 }
209 209
210 210 if (ksi->hki_perfcntr64[i].hki64_ksp != NULL) {
211 211 kstat_delete(ksi->hki_perfcntr64[i].hki64_ksp);
212 212 }
213 213 }
214 214
215 215 /* Delete the "counter" kstats (one per port) */
216 216 kstat_delete(ksi->hki_cntr_ksp);
217 217
218 218 cv_destroy(&ksi->hki_perfcntr64_cv);
219 219 mutex_destroy(&ksi->hki_perfcntr64_lock);
220 220
221 221 /* Free the kstat info structure */
222 222 kmem_free(ksi, sizeof (hermon_ks_info_t));
223 223 }
224 224
225 225
226 226 /*
227 227 * hermon_kstat_picN_create()
228 228 * Context: Only called from attach() path context
229 229 */
230 230 static kstat_t *
231 231 hermon_kstat_picN_create(hermon_state_t *state, int num_pic, int num_evt,
232 232 hermon_ks_mask_t *ev_array)
233 233 {
234 234 kstat_t *picN_ksp;
235 235 struct kstat_named *pic_named_data;
236 236 int drv_instance, i;
237 237 char *drv_name;
238 238 char pic_name[16];
239 239
240 240 /*
241 241 * Create the "picN" kstat. In the steps, below we will attach
242 242 * all of our named event types to it.
243 243 */
244 244 drv_name = (char *)ddi_driver_name(state->hs_dip);
245 245 drv_instance = ddi_get_instance(state->hs_dip);
246 246 (void) sprintf(pic_name, "pic%d", num_pic);
247 247 picN_ksp = kstat_create(drv_name, drv_instance, pic_name, "bus",
248 248 KSTAT_TYPE_NAMED, num_evt, NULL);
249 249 if (picN_ksp == NULL) {
250 250 return (NULL);
251 251 }
252 252 pic_named_data = (struct kstat_named *)(picN_ksp->ks_data);
253 253
254 254 /*
255 255 * Write event names and their associated pcr masks. The last entry
256 256 * in the array (clear_pic) is added separately below (as its pic
257 257 * value must be inverted).
258 258 */
259 259 for (i = 0; i < num_evt - 1; i++) {
260 260 pic_named_data[i].value.ui64 =
261 261 ((uint64_t)i << (num_pic * HERMON_CNTR_SIZE));
262 262 kstat_named_init(&pic_named_data[i], ev_array[i].ks_evt_name,
263 263 KSTAT_DATA_UINT64);
264 264 }
265 265
266 266 /* Add the "clear_pic" entry */
267 267 pic_named_data[i].value.ui64 =
268 268 ~((uint64_t)HERMON_CNTR_MASK << (num_pic * HERMON_CNTR_SIZE));
269 269 kstat_named_init(&pic_named_data[i], ev_array[i].ks_evt_name,
270 270 KSTAT_DATA_UINT64);
271 271
272 272 /* Install the kstat */
273 273 kstat_install(picN_ksp);
274 274
275 275 return (picN_ksp);
276 276 }
277 277
278 278
279 279 /*
280 280 * hermon_kstat_cntr_create()
281 281 * Context: Only called from attach() path context
282 282 */
283 283 static kstat_t *
284 284 hermon_kstat_cntr_create(hermon_state_t *state, int num_pic,
285 285 int (*update)(kstat_t *, int))
286 286 {
287 287 struct kstat *cntr_ksp;
288 288 struct kstat_named *cntr_named_data;
289 289 int drv_instance, i;
290 290 char *drv_name;
291 291 char pic_str[16];
292 292
293 293 /*
294 294 * Create the "counters" kstat. In the steps, below we will attach
295 295 * all of our "pic" to it. Note: The size of this kstat is
296 296 * num_pic + 1 because it also contains the "%pcr".
297 297 */
298 298 drv_name = (char *)ddi_driver_name(state->hs_dip);
299 299 drv_instance = ddi_get_instance(state->hs_dip);
300 300 cntr_ksp = kstat_create(drv_name, drv_instance, "counters", "bus",
301 301 KSTAT_TYPE_NAMED, num_pic + 1, KSTAT_FLAG_WRITABLE);
302 302 if (cntr_ksp == NULL) {
303 303 return (NULL);
304 304 }
305 305 cntr_named_data = (struct kstat_named *)(cntr_ksp->ks_data);
306 306
307 307 /*
308 308 * Initialize the named kstats (for the "pcr" and for the
309 309 * individual "pic" kstats)
310 310 */
311 311 kstat_named_init(&cntr_named_data[0], "pcr", KSTAT_DATA_UINT64);
312 312 for (i = 0; i < num_pic; i++) {
313 313 (void) sprintf(pic_str, "pic%d", i);
314 314 kstat_named_init(&cntr_named_data[i+1], pic_str,
315 315 KSTAT_DATA_UINT64);
316 316 }
317 317
318 318 /*
319 319 * Store the Hermon softstate pointer in the kstat's private field so
320 320 * that it is available to the update function.
321 321 */
322 322 cntr_ksp->ks_private = (void *)state;
323 323 cntr_ksp->ks_update = update;
324 324
325 325 /* Install the kstat */
326 326 kstat_install(cntr_ksp);
327 327
328 328 return (cntr_ksp);
329 329 }
330 330
331 331
332 332 /*
333 333 * hermon_kstat_cntr_update()
334 334 * Context: Called from the kstat context
335 335 */
336 336 static int
337 337 hermon_kstat_cntr_update(kstat_t *ksp, int rw)
338 338 {
339 339 hermon_state_t *state;
340 340 hermon_ks_mask_t *ib_perf;
341 341 hermon_ks_info_t *ksi;
342 342 struct kstat_named *data;
↓ open down ↓ |
342 lines elided |
↑ open up ↑ |
343 343 uint64_t pcr;
344 344 uint32_t tmp;
345 345 uint32_t oldval;
346 346 uint_t numports, indx;
347 347 int status;
348 348 hermon_hw_sm_perfcntr_t sm_perfcntr;
349 349
350 350 /*
351 351 * Extract the Hermon softstate pointer, kstat data, pointer to the
352 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.
353 + * from the input parameters.
356 354 */
357 355 state = ksp->ks_private;
358 356 data = (struct kstat_named *)(ksp->ks_data);
359 357 ksi = state->hs_ks_info;
360 358 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 359
365 360 /*
366 361 * Depending on whether we are reading the "pic" counters or
367 362 * writing the "pcr" control register, we need to handle and
368 363 * fill in the kstat data appropriately.
369 364 *
370 365 * If this is a write to the "pcr", then extract the value from
371 366 * the kstat data and store it in the kstat info structure.
372 367 *
373 368 * Otherwise, if this is a read of the "pic" counter(s), then
374 369 * extract the register offset, size, and mask values from the
375 370 * ib_perf[] array. Then read the corresponding register and store
376 371 * it into the kstat data. Note: We only read/fill in pic1 if more
377 372 * than one port is configured.
378 373 */
379 374 numports = state->hs_cfg_profile->cp_num_ports;
380 375 if (rw == KSTAT_WRITE) {
381 376 /* Update the stored "pcr" value */
382 377 ksi->hki_pcr = data[0].value.ui64;
383 378 return (0);
384 379 } else {
385 380 /*
386 381 * Get the current "pcr" value and extract the lower
387 382 * portion (corresponding to the counters for "pic0")
388 383 */
389 384 pcr = ksi->hki_pcr;
390 385 indx = pcr & HERMON_CNTR_MASK;
391 386 data[0].value.ui64 = pcr;
392 387
393 388 /*
394 389 * Fill in the "pic0" counter, corresponding to port 1.
395 390 * This involves reading in the current value in the register
396 391 * and calculating how many events have happened since this
397 392 * register was last polled. Then we save away the current
398 393 * value for the counter and increment the "pic0" total by
399 394 * the number of new events.
400 395 */
401 396 oldval = ib_perf[indx].ks_old_pic0;
402 397
403 398 status = hermon_getperfcntr_cmd_post(state, 1,
404 399 HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
405 400 if (status != HERMON_CMD_SUCCESS) {
406 401 return (-1);
407 402 }
408 403 switch (indx) {
409 404 case 0: /* port_xmit_data */
410 405 tmp = sm_perfcntr.portxmdata;
411 406 break;
412 407 case 1: /* port_recv_data */
413 408 tmp = sm_perfcntr.portrcdata;
414 409 break;
415 410 case 2: /* port_xmit_pkts */
416 411 tmp = sm_perfcntr.portxmpkts;
417 412 break;
418 413 case 3: /* port_recv_pkts */
419 414 tmp = sm_perfcntr.portrcpkts;
420 415 break;
421 416 case 4: /* port_recv_err */
422 417 tmp = sm_perfcntr.portrcv;
423 418 break;
424 419 case 5: /* port_xmit_discards */
425 420 tmp = sm_perfcntr.portxmdiscard;
426 421 break;
427 422 case 6: /* vl15_dropped */
428 423 tmp = sm_perfcntr.vl15drop;
429 424 break;
430 425 case 7: /* port_xmit_wait */
431 426 tmp = sm_perfcntr.portxmwait;
432 427 break;
433 428 case 8: /* port_recv_remote_phys_err */
434 429 tmp = sm_perfcntr.portrcvrem;
435 430 break;
436 431 case 9: /* port_xmit_constraint_err */
437 432 tmp = sm_perfcntr.portxmconstr;
438 433 break;
439 434 case 10: /* port_recv_constraint_err */
440 435 tmp = sm_perfcntr.portrcconstr;
441 436 break;
442 437 case 11: /* symbol_err_counter */
443 438 tmp = sm_perfcntr.symerr;
444 439 break;
445 440 case 12: /* link_err_recovery_cnt */
446 441 tmp = sm_perfcntr.linkerrrec;
447 442 break;
448 443 case 13: /* link_downed_cnt */
449 444 tmp = sm_perfcntr.linkdown;
450 445 break;
451 446 case 14: /* excessive_buffer_overruns */
452 447 tmp = sm_perfcntr.xsbuffovrun;
453 448 break;
454 449 case 15: /* local_link_integrity_err */
455 450 tmp = sm_perfcntr.locallinkint;
456 451 break;
457 452 case 16: /* clear_pic */
458 453 tmp = 0; /* XXX */
459 454 break;
460 455 default:
461 456 cmn_err(CE_CONT, "perf counter out of range\n");
462 457 }
463 458
464 459 ib_perf[indx].ks_old_pic0 = tmp;
465 460
466 461 tmp = tmp - oldval;
467 462 ksi->hki_pic0 += tmp;
468 463 data[1].value.ui64 = ksi->hki_pic0;
469 464
470 465 /*
471 466 * If necessary, fill in the "pic1" counter for port 2.
472 467 * This works the same as above except that we extract the
473 468 * upper bits (corresponding to the counters for "pic1")
474 469 */
475 470 if (numports == HERMON_MAX_PORTS) {
476 471 indx = pcr >> HERMON_CNTR_SIZE;
477 472 oldval = ib_perf[indx].ks_old_pic1;
478 473
479 474 status = hermon_getperfcntr_cmd_post(state, 2,
480 475 HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
481 476 if (status != HERMON_CMD_SUCCESS) {
482 477 return (-1);
483 478 }
484 479 switch (indx) {
485 480 case 0: /* port_xmit_data */
486 481 tmp = sm_perfcntr.portxmdata;
487 482 break;
488 483 case 1: /* port_recv_data */
489 484 tmp = sm_perfcntr.portrcdata;
490 485 break;
491 486 case 2: /* port_xmit_pkts */
492 487 tmp = sm_perfcntr.portxmpkts;
493 488 break;
494 489 case 3: /* port_recv_pkts */
495 490 tmp = sm_perfcntr.portrcpkts;
496 491 break;
497 492 case 4: /* port_recv_err */
498 493 tmp = sm_perfcntr.portrcv;
499 494 break;
500 495 case 5: /* port_xmit_discards */
501 496 tmp = sm_perfcntr.portxmdiscard;
502 497 break;
503 498 case 6: /* vl15_dropped */
504 499 tmp = sm_perfcntr.vl15drop;
505 500 break;
506 501 case 7: /* port_xmit_wait */
507 502 tmp = sm_perfcntr.portxmwait;
508 503 break;
509 504 case 8: /* port_recv_remote_phys_err */
510 505 tmp = sm_perfcntr.portrcvrem;
511 506 break;
512 507 case 9: /* port_xmit_constraint_err */
513 508 tmp = sm_perfcntr.portxmconstr;
514 509 break;
515 510 case 10: /* port_recv_constraint_err */
516 511 tmp = sm_perfcntr.portrcconstr;
517 512 break;
518 513 case 11: /* symbol_err_counter */
519 514 tmp = sm_perfcntr.symerr;
520 515 break;
521 516 case 12: /* link_err_recovery_cnt */
522 517 tmp = sm_perfcntr.linkerrrec;
523 518 break;
524 519 case 13: /* link_downed_cnt */
525 520 tmp = sm_perfcntr.linkdown;
526 521 break;
527 522 case 14: /* excessive_buffer_overruns */
528 523 tmp = sm_perfcntr.xsbuffovrun;
529 524 break;
530 525 case 15: /* local_link_integrity_err */
531 526 tmp = sm_perfcntr.locallinkint;
532 527 break;
533 528 case 16: /* clear_pic */
534 529 tmp = 0; /* XXX */
535 530 break;
536 531 default:
537 532 cmn_err(CE_CONT, "perf counter out of range\n");
538 533 }
539 534
540 535 ib_perf[indx].ks_old_pic1 = tmp;
541 536
542 537 tmp = tmp - oldval;
543 538 ksi->hki_pic1 += tmp;
544 539 data[2].value.ui64 = ksi->hki_pic1;
545 540 }
546 541
547 542 return (0);
548 543 }
549 544 }
550 545
551 546 /*
552 547 * 64 bit kstats for performance counters:
553 548 *
554 549 * Export 64 bit performance counters in kstats.
555 550 *
556 551 * If the HCA hardware supports 64 bit extended port counters, we use the
557 552 * hardware based counters. If the HCA hardware does not support extended port
558 553 * counters, we maintain 64 bit performance counters in software using the
559 554 * 32 bit hardware port counters.
560 555 *
561 556 * The software based counters are maintained as follows:
562 557 *
563 558 * We create a thread that, every one second, reads the values of 32 bit
564 559 * hardware counters and adds them to the 64 bit software counters. Immediately
565 560 * after reading, it resets the 32 bit hardware counters to zero (so that they
566 561 * start counting from zero again). At any time the current value of a counter
567 562 * is going to be the sum of the 64 bit software counter and the 32 bit
568 563 * hardware counter.
569 564 *
570 565 * Since this work need not be done if there is no consumer, by default
571 566 * we do not maintain 64 bit software counters. To enable this the consumer
572 567 * needs to write a non-zero value to the "enable" component of the of
573 568 * perf_counters kstat. Writing zero to this component will disable this work.
574 569 * NOTE: The enabling or disabling applies to software based counters only.
575 570 * Hardware based counters counters are always enabled.
576 571 *
577 572 * If performance monitor is enabled in subnet manager, the SM could
578 573 * periodically reset the hardware counters by sending perf-MADs. So only
579 574 * one of either our software 64 bit counters or the SM performance monitor
580 575 * could be enabled at the same time. However, if both of them are enabled at
581 576 * the same time we still do our best by keeping track of the values of the
582 577 * last read 32 bit hardware counters. If the current read of a 32 bit hardware
583 578 * counter is less than the last read of the counter, we ignore the current
584 579 * value and go with the last read value.
585 580 */
586 581
587 582 /*
588 583 * hermon_kstat_perfcntr64_create()
589 584 * Context: Only called from attach() path context
590 585 *
591 586 * Create "port#/perf_counters" kstat for the specified port number.
592 587 */
593 588 void
594 589 hermon_kstat_perfcntr64_create(hermon_state_t *state, uint_t port_num)
595 590 {
596 591 hermon_ks_info_t *ksi = state->hs_ks_info;
597 592 struct kstat *cntr_ksp;
598 593 struct kstat_named *cntr_named_data;
599 594 int drv_instance;
600 595 char *drv_name;
601 596 char kname[32];
602 597 int status, ext_width_supported;
603 598
604 599 ASSERT(port_num != 0);
605 600
606 601 status = hermon_is_ext_port_counters_supported(state, port_num,
607 602 HERMON_CMD_NOSLEEP_SPIN, &ext_width_supported);
608 603 if (status == HERMON_CMD_SUCCESS) {
609 604 ksi->hki_perfcntr64[port_num - 1].
610 605 hki64_ext_port_counters_supported = ext_width_supported;
611 606 }
612 607
613 608 drv_name = (char *)ddi_driver_name(state->hs_dip);
614 609 drv_instance = ddi_get_instance(state->hs_dip);
615 610 (void) snprintf(kname, sizeof (kname), "port%u/perf_counters",
616 611 port_num);
617 612 cntr_ksp = kstat_create(drv_name, drv_instance, kname, "ib",
618 613 KSTAT_TYPE_NAMED, HERMON_PERFCNTR64_NUM_COUNTERS,
619 614 KSTAT_FLAG_WRITABLE);
620 615 if (cntr_ksp == NULL) {
621 616 return;
622 617 }
623 618 cntr_named_data = (struct kstat_named *)(cntr_ksp->ks_data);
624 619
625 620 kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_ENABLE_IDX],
626 621 "enable", KSTAT_DATA_UINT32);
627 622 kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_XMIT_DATA_IDX],
628 623 "xmit_data", KSTAT_DATA_UINT64);
629 624 kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_RECV_DATA_IDX],
630 625 "recv_data", KSTAT_DATA_UINT64);
631 626 kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_XMIT_PKTS_IDX],
632 627 "xmit_pkts", KSTAT_DATA_UINT64);
633 628 kstat_named_init(&cntr_named_data[HERMON_PERFCNTR64_RECV_PKTS_IDX],
634 629 "recv_pkts", KSTAT_DATA_UINT64);
635 630
636 631 ksi->hki_perfcntr64[port_num - 1].hki64_ksp = cntr_ksp;
637 632 ksi->hki_perfcntr64[port_num - 1].hki64_port_num = port_num;
638 633 ksi->hki_perfcntr64[port_num - 1].hki64_state = state;
639 634
640 635 cntr_ksp->ks_private = &ksi->hki_perfcntr64[port_num - 1];
641 636 cntr_ksp->ks_update = hermon_kstat_perfcntr64_update;
642 637
643 638 /* Install the kstat */
644 639 kstat_install(cntr_ksp);
645 640 }
646 641
647 642 /*
648 643 * hermon_kstat_perfcntr64_read()
649 644 *
650 645 * Read the values of 32 bit hardware counters.
651 646 *
652 647 * If reset is true, reset the 32 bit hardware counters. Add the values of the
653 648 * 32 bit hardware counters to the 64 bit software counters.
654 649 *
655 650 * If reset is false, just save the values read from the 32 bit hardware
656 651 * counters in hki64_last_read[].
657 652 *
658 653 * See the general comment on the 64 bit performance counters
659 654 * regarding the use of last read 32 bit hardware counter values.
660 655 */
661 656 static int
662 657 hermon_kstat_perfcntr64_read(hermon_state_t *state, uint_t port, int reset)
663 658 {
664 659 hermon_ks_info_t *ksi = state->hs_ks_info;
665 660 hermon_perfcntr64_ks_info_t *ksi64 = &ksi->hki_perfcntr64[port - 1];
666 661 int status, i;
667 662 uint32_t tmp;
668 663 hermon_hw_sm_perfcntr_t sm_perfcntr;
669 664
670 665 ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock));
671 666 ASSERT(port != 0);
672 667
673 668 /* read the 32 bit hardware counters */
674 669 status = hermon_getperfcntr_cmd_post(state, port,
675 670 HERMON_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
676 671 if (status != HERMON_CMD_SUCCESS) {
677 672 return (status);
678 673 }
679 674
680 675 if (reset) {
681 676 /* reset the hardware counters */
682 677 status = hermon_getperfcntr_cmd_post(state, port,
683 678 HERMON_CMD_NOSLEEP_SPIN, NULL, 1);
684 679 if (status != HERMON_CMD_SUCCESS) {
685 680 return (status);
686 681 }
687 682
688 683 /*
689 684 * Update 64 bit software counters
690 685 */
691 686 tmp = MAX(sm_perfcntr.portxmdata,
692 687 ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX]);
693 688 ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_DATA_IDX] += tmp;
694 689
695 690 tmp = MAX(sm_perfcntr.portrcdata,
696 691 ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX]);
697 692 ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_DATA_IDX] += tmp;
698 693
699 694 tmp = MAX(sm_perfcntr.portxmpkts,
700 695 ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX]);
701 696 ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_PKTS_IDX] += tmp;
702 697
703 698 tmp = MAX(sm_perfcntr.portrcpkts,
704 699 ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX]);
705 700 ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_PKTS_IDX] += tmp;
706 701
707 702 for (i = 0; i < HERMON_PERFCNTR64_NUM_COUNTERS; i++)
708 703 ksi64->hki64_last_read[i] = 0;
709 704
710 705 } else {
711 706 /*
712 707 * Update ksi64->hki64_last_read[]
713 708 */
714 709 SET_TO_MAX(
715 710 ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX],
716 711 sm_perfcntr.portxmdata);
717 712
718 713 SET_TO_MAX(
719 714 ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX],
720 715 sm_perfcntr.portrcdata);
721 716
722 717 SET_TO_MAX(
723 718 ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX],
724 719 sm_perfcntr.portxmpkts);
725 720
726 721 SET_TO_MAX(
727 722 ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX],
728 723 sm_perfcntr.portrcpkts);
729 724 }
730 725
731 726 return (HERMON_CMD_SUCCESS);
732 727 }
733 728
734 729 /*
735 730 * hermon_kstat_perfcntr64_update_thread()
736 731 * Context: Entry point for a kernel thread
737 732 *
738 733 * Maintain 64 bit performance counters in software using the 32 bit
739 734 * hardware counters.
740 735 */
741 736 static void
742 737 hermon_kstat_perfcntr64_update_thread(void *arg)
743 738 {
744 739 hermon_state_t *state = (hermon_state_t *)arg;
745 740 hermon_ks_info_t *ksi = state->hs_ks_info;
746 741 uint_t i;
747 742 clock_t delta = drv_usectohz(1000000);
748 743
749 744 mutex_enter(&ksi->hki_perfcntr64_lock);
750 745 /*
751 746 * Every one second update the values 64 bit software counters
752 747 * for all ports. Exit if HERMON_PERFCNTR64_THREAD_EXIT flag is set.
753 748 */
754 749 while (!(ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_EXIT)) {
755 750 for (i = 0; i < state->hs_cfg_profile->cp_num_ports; i++) {
756 751 if (ksi->hki_perfcntr64[i].hki64_enabled) {
757 752 (void) hermon_kstat_perfcntr64_read(state,
758 753 i + 1, 1);
759 754 }
760 755 }
761 756 /* sleep for a second */
762 757 (void) cv_reltimedwait(&ksi->hki_perfcntr64_cv,
763 758 &ksi->hki_perfcntr64_lock, delta, TR_CLOCK_TICK);
764 759 }
765 760 ksi->hki_perfcntr64_flags = 0;
766 761 mutex_exit(&ksi->hki_perfcntr64_lock);
767 762 }
768 763
769 764 /*
770 765 * hermon_kstat_perfcntr64_thread_create()
771 766 * Context: Called from the kstat context
772 767 *
773 768 * Create a thread that maintains 64 bit performance counters in software.
774 769 */
775 770 static void
776 771 hermon_kstat_perfcntr64_thread_create(hermon_state_t *state)
777 772 {
778 773 hermon_ks_info_t *ksi = state->hs_ks_info;
779 774 kthread_t *thr;
780 775
781 776 ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock));
782 777
783 778 /*
784 779 * One thread per hermon instance. Don't create a thread if already
785 780 * created.
786 781 */
787 782 if (!(ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_CREATED)) {
788 783 thr = thread_create(NULL, 0,
789 784 hermon_kstat_perfcntr64_update_thread,
790 785 state, 0, &p0, TS_RUN, minclsyspri);
791 786 ksi->hki_perfcntr64_thread_id = thr->t_did;
792 787 ksi->hki_perfcntr64_flags |= HERMON_PERFCNTR64_THREAD_CREATED;
793 788 }
794 789 }
795 790
796 791 /*
797 792 * hermon_kstat_perfcntr64_thread_exit()
798 793 * Context: Called from attach, detach or kstat context
799 794 */
800 795 static void
801 796 hermon_kstat_perfcntr64_thread_exit(hermon_ks_info_t *ksi)
802 797 {
803 798 kt_did_t tid;
804 799
805 800 ASSERT(MUTEX_HELD(&ksi->hki_perfcntr64_lock));
806 801
807 802 if (ksi->hki_perfcntr64_flags & HERMON_PERFCNTR64_THREAD_CREATED) {
808 803 /*
809 804 * Signal the thread to exit and wait until the thread exits.
810 805 */
811 806 ksi->hki_perfcntr64_flags |= HERMON_PERFCNTR64_THREAD_EXIT;
812 807 tid = ksi->hki_perfcntr64_thread_id;
813 808 cv_signal(&ksi->hki_perfcntr64_cv);
814 809
815 810 mutex_exit(&ksi->hki_perfcntr64_lock);
816 811 thread_join(tid);
817 812 mutex_enter(&ksi->hki_perfcntr64_lock);
818 813 }
819 814 }
820 815
821 816 /*
822 817 * hermon_kstat_perfcntr64_update_ext()
823 818 * Context: Called from the kstat context
824 819 *
825 820 * Update perf_counters kstats with the values of the extended port counters
826 821 * from the hardware.
827 822 */
828 823 static int
829 824 hermon_kstat_perfcntr64_update_ext(hermon_perfcntr64_ks_info_t *ksi64, int rw,
830 825 struct kstat_named *data)
831 826 {
832 827 hermon_hw_sm_extperfcntr_t sm_extperfcntr;
833 828
834 829 /*
835 830 * The "enable" component of the kstat is the only writable kstat.
836 831 * It is a no-op when the hardware supports extended port counters.
837 832 */
838 833 if (rw == KSTAT_WRITE)
839 834 return (0);
840 835
841 836 /*
842 837 * Read the counters and update kstats.
843 838 */
844 839 if (hermon_getextperfcntr_cmd_post(ksi64->hki64_state,
845 840 ksi64->hki64_port_num, HERMON_CMD_NOSLEEP_SPIN, &sm_extperfcntr) !=
846 841 HERMON_CMD_SUCCESS) {
847 842 return (EIO);
848 843 }
849 844
850 845 data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 1;
851 846
852 847 data[HERMON_PERFCNTR64_XMIT_DATA_IDX].value.ui64 =
853 848 sm_extperfcntr.portxmdata;
854 849
855 850 data[HERMON_PERFCNTR64_RECV_DATA_IDX].value.ui64 =
856 851 sm_extperfcntr.portrcdata;
857 852
858 853 data[HERMON_PERFCNTR64_XMIT_PKTS_IDX].value.ui64 =
859 854 sm_extperfcntr.portxmpkts;
860 855
861 856 data[HERMON_PERFCNTR64_RECV_PKTS_IDX].value.ui64 =
862 857 sm_extperfcntr.portrcpkts;
863 858
864 859 return (0);
865 860 }
866 861
867 862 /*
868 863 * hermon_kstat_perfcntr64_update()
869 864 * Context: Called from the kstat context
870 865 *
871 866 * See the general comment on 64 bit kstats for performance counters:
872 867 */
873 868 static int
874 869 hermon_kstat_perfcntr64_update(kstat_t *ksp, int rw)
875 870 {
876 871 hermon_state_t *state;
877 872 struct kstat_named *data;
878 873 hermon_ks_info_t *ksi;
879 874 hermon_perfcntr64_ks_info_t *ksi64;
880 875 int i, thr_exit;
881 876 int rv;
882 877
883 878 ksi64 = ksp->ks_private;
884 879 state = ksi64->hki64_state;
885 880 ksi = state->hs_ks_info;
886 881 data = (struct kstat_named *)(ksp->ks_data);
887 882
888 883 mutex_enter(&ksi->hki_perfcntr64_lock);
889 884
890 885 if (ksi64->hki64_ext_port_counters_supported) {
891 886 rv = hermon_kstat_perfcntr64_update_ext(ksi64, rw, data);
892 887 mutex_exit(&ksi->hki_perfcntr64_lock);
893 888 return (rv);
894 889 }
895 890
896 891 /*
897 892 * 64 bit performance counters maintained by the software is not
898 893 * enabled by default. Enable them upon a writing a non-zero value
899 894 * to "enable" kstat. Disable them upon a writing zero to the
900 895 * "enable" kstat.
901 896 */
902 897 if (rw == KSTAT_WRITE) {
903 898 if (data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32) {
904 899 if (ksi64->hki64_enabled == 0) {
905 900 /*
906 901 * Reset the hardware counters to ensure that
907 902 * the hardware counter doesn't max out
908 903 * (and hence stop counting) before we get
909 904 * a chance to reset the counter in
910 905 * hermon_kstat_perfcntr64_update_thread.
911 906 */
912 907 if (hermon_getperfcntr_cmd_post(state,
913 908 ksi64->hki64_port_num,
914 909 HERMON_CMD_NOSLEEP_SPIN, NULL, 1) !=
915 910 HERMON_CMD_SUCCESS) {
916 911 mutex_exit(&ksi->hki_perfcntr64_lock);
917 912 return (EIO);
918 913 }
919 914
920 915 /* Enable 64 bit software counters */
921 916 ksi64->hki64_enabled = 1;
922 917 for (i = 0;
923 918 i < HERMON_PERFCNTR64_NUM_COUNTERS; i++) {
924 919 ksi64->hki64_counters[i] = 0;
925 920 ksi64->hki64_last_read[i] = 0;
926 921 }
927 922 hermon_kstat_perfcntr64_thread_create(state);
928 923 }
929 924
930 925 } else if (ksi64->hki64_enabled) {
931 926 /* Disable 64 bit software counters */
932 927 ksi64->hki64_enabled = 0;
933 928 thr_exit = 1;
934 929 for (i = 0; i < state->hs_cfg_profile->cp_num_ports;
935 930 i++) {
936 931 if (ksi->hki_perfcntr64[i].hki64_enabled) {
937 932 thr_exit = 0;
938 933 break;
939 934 }
940 935 }
941 936 if (thr_exit)
942 937 hermon_kstat_perfcntr64_thread_exit(ksi);
943 938 }
944 939 } else if (ksi64->hki64_enabled) {
945 940 /*
946 941 * Read the counters and update kstats.
947 942 */
948 943 if (hermon_kstat_perfcntr64_read(state, ksi64->hki64_port_num,
949 944 0) != HERMON_CMD_SUCCESS) {
950 945 mutex_exit(&ksi->hki_perfcntr64_lock);
951 946 return (EIO);
952 947 }
953 948
954 949 data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 1;
955 950
956 951 data[HERMON_PERFCNTR64_XMIT_DATA_IDX].value.ui64 =
957 952 ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_DATA_IDX] +
958 953 ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_DATA_IDX];
959 954
960 955 data[HERMON_PERFCNTR64_RECV_DATA_IDX].value.ui64 =
961 956 ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_DATA_IDX] +
962 957 ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_DATA_IDX];
963 958
964 959 data[HERMON_PERFCNTR64_XMIT_PKTS_IDX].value.ui64 =
965 960 ksi64->hki64_counters[HERMON_PERFCNTR64_XMIT_PKTS_IDX] +
966 961 ksi64->hki64_last_read[HERMON_PERFCNTR64_XMIT_PKTS_IDX];
967 962
968 963 data[HERMON_PERFCNTR64_RECV_PKTS_IDX].value.ui64 =
969 964 ksi64->hki64_counters[HERMON_PERFCNTR64_RECV_PKTS_IDX] +
970 965 ksi64->hki64_last_read[HERMON_PERFCNTR64_RECV_PKTS_IDX];
971 966
972 967 } else {
973 968 /* return 0 in kstats if not enabled */
974 969 data[HERMON_PERFCNTR64_ENABLE_IDX].value.ui32 = 0;
975 970 for (i = 1; i < HERMON_PERFCNTR64_NUM_COUNTERS; i++)
976 971 data[i].value.ui64 = 0;
977 972 }
978 973
979 974 mutex_exit(&ksi->hki_perfcntr64_lock);
980 975 return (0);
981 976 }
↓ open down ↓ |
608 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX