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