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