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/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;
↓ open down ↓ |
382 lines elided |
↑ open up ↑ |
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 - * from the input parameters. Note: For warlock purposes, these
394 - * parameters are all accessed only in this routine and are,
395 - * therefore, protected by the lock used by the kstat framework.
393 + * from the input parameters.
396 394 */
397 395 state = ksp->ks_private;
398 396 data = (struct kstat_named *)(ksp->ks_data);
399 397 ksi = state->ts_ks_info;
400 398 ib_perf = &ksi->tki_ib_perfcnt[0];
401 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ksi))
402 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
403 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ib_perf))
404 399
405 400 /*
406 401 * Depending on whether we are reading the "pic" counters or
407 402 * writing the "pcr" control register, we need to handle and
408 403 * fill in the kstat data appropriately.
409 404 *
410 405 * If this is a write to the "pcr", then extract the value from
411 406 * the kstat data and store it in the kstat info structure.
412 407 *
413 408 * Otherwise, if this is a read of the "pic" counter(s), then
414 409 * extract the register offset, size, and mask values from the
415 410 * ib_perf[] array. Then read the corresponding register and store
416 411 * it into the kstat data. Note: We only read/fill in pic1 if more
417 412 * than one port is configured.
418 413 */
419 414 numports = state->ts_cfg_profile->cp_num_ports;
420 415 if (rw == KSTAT_WRITE) {
421 416 /* Update the stored "pcr" value */
422 417 ksi->tki_pcr = data[0].value.ui64;
423 418 TAVOR_TNF_EXIT(tavor_kstat_cntr_update);
424 419 return (0);
425 420 } else {
426 421 /*
427 422 * Get the current "pcr" value and extract the lower
428 423 * portion (corresponding to the counters for "pic0")
429 424 */
430 425 pcr = ksi->tki_pcr;
431 426 indx = pcr & TAVOR_CNTR_MASK;
432 427 data[0].value.ui64 = pcr;
433 428
434 429 /*
435 430 * Fill in the "pic0" counter, corresponding to port 1.
436 431 * This involves reading in the current value in the register
437 432 * and calculating how many events have happened since this
438 433 * register was last polled. Then we save away the current
439 434 * value for the counter and increment the "pic0" total by
440 435 * the number of new events.
441 436 */
442 437 offset = ib_perf[indx].ks_reg_offset;
443 438 shift = ib_perf[indx].ks_reg_shift;
444 439 mask = ib_perf[indx].ks_reg_mask;
445 440 oldval = ib_perf[indx].ks_old_pic0;
446 441
447 442 pic0 = ddi_get32(state->ts_reg_cmdhdl, (uint32_t *)
448 443 (uintptr_t)((uintptr_t)state->ts_reg_cmd_baseaddr +
449 444 offset));
450 445 tmp = ((pic0 >> shift) & mask);
451 446
452 447 ib_perf[indx].ks_old_pic0 = tmp;
453 448
454 449 tmp = tmp - oldval;
455 450 ksi->tki_pic0 += tmp;
456 451 data[1].value.ui64 = ksi->tki_pic0;
457 452
458 453 /*
459 454 * If necessary, fill in the "pic1" counter for port 2.
460 455 * This works the same as above except that we extract the
461 456 * upper bits (corresponding to the counters for "pic1")
462 457 */
463 458 if (numports == TAVOR_NUM_PORTS) {
464 459 indx = pcr >> TAVOR_CNTR_SIZE;
465 460 offset = ib_perf[indx].ks_reg_offset;
466 461 shift = ib_perf[indx].ks_reg_shift;
467 462 mask = ib_perf[indx].ks_reg_mask;
468 463 oldval = ib_perf[indx].ks_old_pic1;
469 464
470 465 pic1 = ddi_get32(state->ts_reg_cmdhdl, (uint32_t *)
471 466 (uintptr_t)((uintptr_t)state->ts_reg_cmd_baseaddr +
472 467 offset + TAVOR_HW_PORT_SIZE));
473 468 tmp = ((pic1 >> shift) & mask);
474 469
475 470 ib_perf[indx].ks_old_pic1 = tmp;
476 471
477 472 tmp = tmp - oldval;
478 473 ksi->tki_pic1 += tmp;
479 474 data[2].value.ui64 = ksi->tki_pic1;
480 475 }
481 476
482 477 TAVOR_TNF_EXIT(tavor_kstat_cntr_update);
483 478 return (0);
484 479 }
485 480 }
486 481
487 482 /*
488 483 * 64 bit kstats for performance counters:
489 484 *
490 485 * Since the hardware as of now does not support 64 bit performance counters,
491 486 * we maintain 64 bit performance counters in software using the 32 bit
492 487 * hardware counters.
493 488 *
494 489 * We create a thread that, every one second, reads the values of 32 bit
495 490 * hardware counters and adds them to the 64 bit software counters. Immediately
496 491 * after reading, it resets the 32 bit hardware counters to zero (so that they
497 492 * start counting from zero again). At any time the current value of a counter
498 493 * is going to be the sum of the 64 bit software counter and the 32 bit
499 494 * hardware counter.
500 495 *
501 496 * Since this work need not be done if there is no consumer, by default
502 497 * we do not maintain 64 bit software counters. To enable this the consumer
503 498 * needs to write a non-zero value to the "enable" component of the of
504 499 * perf_counters kstat. Writing zero to this component will disable this work.
505 500 *
506 501 * If performance monitor is enabled in subnet manager, the SM could
507 502 * periodically reset the hardware counters by sending perf-MADs. So only
508 503 * one of either our software 64 bit counters or the SM performance monitor
509 504 * could be enabled at the same time. However, if both of them are enabled at
510 505 * the same time we still do our best by keeping track of the values of the
511 506 * last read 32 bit hardware counters. If the current read of a 32 bit hardware
512 507 * counter is less than the last read of the counter, we ignore the current
513 508 * value and go with the last read value.
514 509 */
515 510
516 511 /*
517 512 * tavor_kstat_perfcntr64_create()
518 513 * Context: Only called from attach() path context
519 514 *
520 515 * Create "port#/perf_counters" kstat for the specified port number.
521 516 */
522 517 void
523 518 tavor_kstat_perfcntr64_create(tavor_state_t *state, uint_t port_num)
524 519 {
525 520 tavor_ks_info_t *ksi = state->ts_ks_info;
526 521 struct kstat *cntr_ksp;
527 522 struct kstat_named *cntr_named_data;
528 523 int drv_instance;
529 524 char *drv_name;
530 525 char kname[32];
531 526
532 527 ASSERT(port_num != 0);
533 528
534 529 drv_name = (char *)ddi_driver_name(state->ts_dip);
535 530 drv_instance = ddi_get_instance(state->ts_dip);
536 531 (void) snprintf(kname, sizeof (kname), "port%u/perf_counters",
537 532 port_num);
538 533 cntr_ksp = kstat_create(drv_name, drv_instance, kname, "ib",
539 534 KSTAT_TYPE_NAMED, TAVOR_PERFCNTR64_NUM_COUNTERS,
540 535 KSTAT_FLAG_WRITABLE);
541 536 if (cntr_ksp == NULL) {
542 537 return;
543 538 }
544 539 cntr_named_data = (struct kstat_named *)(cntr_ksp->ks_data);
545 540
546 541 kstat_named_init(&cntr_named_data[TAVOR_PERFCNTR64_ENABLE_IDX],
547 542 "enable", KSTAT_DATA_UINT32);
548 543 kstat_named_init(&cntr_named_data[TAVOR_PERFCNTR64_XMIT_DATA_IDX],
549 544 "xmit_data", KSTAT_DATA_UINT64);
550 545 kstat_named_init(&cntr_named_data[TAVOR_PERFCNTR64_RECV_DATA_IDX],
551 546 "recv_data", KSTAT_DATA_UINT64);
552 547 kstat_named_init(&cntr_named_data[TAVOR_PERFCNTR64_XMIT_PKTS_IDX],
553 548 "xmit_pkts", KSTAT_DATA_UINT64);
554 549 kstat_named_init(&cntr_named_data[TAVOR_PERFCNTR64_RECV_PKTS_IDX],
555 550 "recv_pkts", KSTAT_DATA_UINT64);
556 551
557 552 ksi->tki_perfcntr64[port_num - 1].tki64_ksp = cntr_ksp;
558 553 ksi->tki_perfcntr64[port_num - 1].tki64_port_num = port_num;
559 554 ksi->tki_perfcntr64[port_num - 1].tki64_state = state;
560 555
561 556 cntr_ksp->ks_private = &ksi->tki_perfcntr64[port_num - 1];
562 557 cntr_ksp->ks_update = tavor_kstat_perfcntr64_update;
563 558
564 559 /* Install the kstat */
565 560 kstat_install(cntr_ksp);
566 561 }
567 562
568 563 /*
569 564 * tavor_kstat_perfcntr64_read()
570 565 *
571 566 * Read the values of 32 bit hardware counters.
572 567 *
573 568 * If reset is true, reset the 32 bit hardware counters. Add the values of the
574 569 * 32 bit hardware counters to the 64 bit software counters.
575 570 *
576 571 * If reset is false, just save the values read from the 32 bit hardware
577 572 * counters in tki64_last_read[].
578 573 *
579 574 * See the general comment on the 64 bit performance counters
580 575 * regarding the use of last read 32 bit hardware counter values.
581 576 */
582 577 static int
583 578 tavor_kstat_perfcntr64_read(tavor_state_t *state, uint_t port, int reset)
584 579 {
585 580 tavor_ks_info_t *ksi = state->ts_ks_info;
586 581 tavor_perfcntr64_ks_info_t *ksi64 = &ksi->tki_perfcntr64[port - 1];
587 582 int status, i;
588 583 uint32_t tmp;
589 584 tavor_hw_sm_perfcntr_t sm_perfcntr;
590 585
591 586 ASSERT(MUTEX_HELD(&ksi->tki_perfcntr64_lock));
592 587 ASSERT(port != 0);
593 588
594 589 /* read the 32 bit hardware counters */
595 590 status = tavor_getperfcntr_cmd_post(state, port,
596 591 TAVOR_CMD_NOSLEEP_SPIN, &sm_perfcntr, 0);
597 592 if (status != TAVOR_CMD_SUCCESS) {
598 593 return (status);
599 594 }
600 595
601 596 if (reset) {
602 597 /* reset the hardware counters */
603 598 status = tavor_getperfcntr_cmd_post(state, port,
604 599 TAVOR_CMD_NOSLEEP_SPIN, NULL, 1);
605 600 if (status != TAVOR_CMD_SUCCESS) {
606 601 return (status);
607 602 }
608 603
609 604 /*
610 605 * Update 64 bit software counters
611 606 */
612 607 tmp = MAX(sm_perfcntr.portxmdata,
613 608 ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_DATA_IDX]);
614 609 ksi64->tki64_counters[TAVOR_PERFCNTR64_XMIT_DATA_IDX] += tmp;
615 610
616 611 tmp = MAX(sm_perfcntr.portrcdata,
617 612 ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_DATA_IDX]);
618 613 ksi64->tki64_counters[TAVOR_PERFCNTR64_RECV_DATA_IDX] += tmp;
619 614
620 615 tmp = MAX(sm_perfcntr.portxmpkts,
621 616 ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_PKTS_IDX]);
622 617 ksi64->tki64_counters[TAVOR_PERFCNTR64_XMIT_PKTS_IDX] += tmp;
623 618
624 619 tmp = MAX(sm_perfcntr.portrcpkts,
625 620 ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_PKTS_IDX]);
626 621 ksi64->tki64_counters[TAVOR_PERFCNTR64_RECV_PKTS_IDX] += tmp;
627 622
628 623 for (i = 0; i < TAVOR_PERFCNTR64_NUM_COUNTERS; i++)
629 624 ksi64->tki64_last_read[i] = 0;
630 625
631 626 } else {
632 627 /*
633 628 * Update ksi64->tki64_last_read[]
634 629 */
635 630 SET_TO_MAX(
636 631 ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_DATA_IDX],
637 632 sm_perfcntr.portxmdata);
638 633
639 634 SET_TO_MAX(
640 635 ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_DATA_IDX],
641 636 sm_perfcntr.portrcdata);
642 637
643 638 SET_TO_MAX(
644 639 ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_PKTS_IDX],
645 640 sm_perfcntr.portxmpkts);
646 641
647 642 SET_TO_MAX(
648 643 ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_PKTS_IDX],
649 644 sm_perfcntr.portrcpkts);
650 645 }
651 646
652 647 return (TAVOR_CMD_SUCCESS);
653 648 }
654 649
655 650 /*
656 651 * tavor_kstat_perfcntr64_update_thread()
657 652 * Context: Entry point for a kernel thread
658 653 *
659 654 * Maintain 64 bit performance counters in software using the 32 bit
660 655 * hardware counters.
661 656 */
662 657 static void
663 658 tavor_kstat_perfcntr64_update_thread(void *arg)
664 659 {
665 660 tavor_state_t *state = (tavor_state_t *)arg;
666 661 tavor_ks_info_t *ksi = state->ts_ks_info;
667 662 uint_t i;
668 663
669 664 mutex_enter(&ksi->tki_perfcntr64_lock);
670 665 /*
671 666 * Every one second update the values 64 bit software counters
672 667 * for all ports. Exit if TAVOR_PERFCNTR64_THREAD_EXIT flag is set.
673 668 */
674 669 while (!(ksi->tki_perfcntr64_flags & TAVOR_PERFCNTR64_THREAD_EXIT)) {
675 670 for (i = 0; i < state->ts_cfg_profile->cp_num_ports; i++) {
676 671 if (ksi->tki_perfcntr64[i].tki64_enabled) {
677 672 (void) tavor_kstat_perfcntr64_read(state,
678 673 i + 1, 1);
679 674 }
680 675 }
681 676 /* sleep for a second */
682 677 (void) cv_timedwait(&ksi->tki_perfcntr64_cv,
683 678 &ksi->tki_perfcntr64_lock,
684 679 ddi_get_lbolt() + drv_usectohz(1000000));
685 680 }
686 681 ksi->tki_perfcntr64_flags = 0;
687 682 mutex_exit(&ksi->tki_perfcntr64_lock);
688 683 }
689 684
690 685 /*
691 686 * tavor_kstat_perfcntr64_thread_create()
692 687 * Context: Called from the kstat context
693 688 *
694 689 * Create a thread that maintains 64 bit performance counters in software.
695 690 */
696 691 static void
697 692 tavor_kstat_perfcntr64_thread_create(tavor_state_t *state)
698 693 {
699 694 tavor_ks_info_t *ksi = state->ts_ks_info;
700 695 kthread_t *thr;
701 696
702 697 ASSERT(MUTEX_HELD(&ksi->tki_perfcntr64_lock));
703 698
704 699 /*
705 700 * One thread per tavor instance. Don't create a thread if already
706 701 * created.
707 702 */
708 703 if (!(ksi->tki_perfcntr64_flags & TAVOR_PERFCNTR64_THREAD_CREATED)) {
709 704 thr = thread_create(NULL, 0,
710 705 tavor_kstat_perfcntr64_update_thread,
711 706 state, 0, &p0, TS_RUN, minclsyspri);
712 707 ksi->tki_perfcntr64_thread_id = thr->t_did;
713 708 ksi->tki_perfcntr64_flags |= TAVOR_PERFCNTR64_THREAD_CREATED;
714 709 }
715 710 }
716 711
717 712 /*
718 713 * tavor_kstat_perfcntr64_thread_exit()
719 714 * Context: Called from attach, detach or kstat context
720 715 */
721 716 static void
722 717 tavor_kstat_perfcntr64_thread_exit(tavor_ks_info_t *ksi)
723 718 {
724 719 kt_did_t tid;
725 720
726 721 ASSERT(MUTEX_HELD(&ksi->tki_perfcntr64_lock));
727 722
728 723 if (ksi->tki_perfcntr64_flags & TAVOR_PERFCNTR64_THREAD_CREATED) {
729 724 /*
730 725 * Signal the thread to exit and wait until the thread exits.
731 726 */
732 727 ksi->tki_perfcntr64_flags |= TAVOR_PERFCNTR64_THREAD_EXIT;
733 728 tid = ksi->tki_perfcntr64_thread_id;
734 729 cv_signal(&ksi->tki_perfcntr64_cv);
735 730
736 731 mutex_exit(&ksi->tki_perfcntr64_lock);
737 732 thread_join(tid);
738 733 mutex_enter(&ksi->tki_perfcntr64_lock);
739 734 }
740 735 }
741 736
742 737 /*
743 738 * tavor_kstat_perfcntr64_update()
744 739 * Context: Called from the kstat context
745 740 *
746 741 * See the general comment on 64 bit kstats for performance counters:
747 742 */
748 743 static int
749 744 tavor_kstat_perfcntr64_update(kstat_t *ksp, int rw)
750 745 {
751 746 tavor_state_t *state;
752 747 struct kstat_named *data;
753 748 tavor_ks_info_t *ksi;
754 749 tavor_perfcntr64_ks_info_t *ksi64;
755 750 int i, thr_exit;
756 751
757 752 ksi64 = ksp->ks_private;
758 753 state = ksi64->tki64_state;
759 754 ksi = state->ts_ks_info;
760 755 data = (struct kstat_named *)(ksp->ks_data);
761 756
762 757 mutex_enter(&ksi->tki_perfcntr64_lock);
763 758
764 759 /*
765 760 * 64 bit performance counters maintained by the software is not
766 761 * enabled by default. Enable them upon a writing a non-zero value
767 762 * to "enable" kstat. Disable them upon a writing zero to the
768 763 * "enable" kstat.
769 764 */
770 765 if (rw == KSTAT_WRITE) {
771 766 if (data[TAVOR_PERFCNTR64_ENABLE_IDX].value.ui32) {
772 767 if (ksi64->tki64_enabled == 0) {
773 768 /*
774 769 * Reset the hardware counters to ensure that
775 770 * the hardware counter doesn't max out
776 771 * (and hence stop counting) before we get
777 772 * a chance to reset the counter in
778 773 * tavor_kstat_perfcntr64_update_thread.
779 774 */
780 775 if (tavor_getperfcntr_cmd_post(state,
781 776 ksi64->tki64_port_num,
782 777 TAVOR_CMD_NOSLEEP_SPIN, NULL, 1) !=
783 778 TAVOR_CMD_SUCCESS) {
784 779 mutex_exit(&ksi->tki_perfcntr64_lock);
785 780 return (EIO);
786 781 }
787 782
788 783 /* Enable 64 bit software counters */
789 784 ksi64->tki64_enabled = 1;
790 785 for (i = 0;
791 786 i < TAVOR_PERFCNTR64_NUM_COUNTERS; i++) {
792 787 ksi64->tki64_counters[i] = 0;
793 788 ksi64->tki64_last_read[i] = 0;
794 789 }
795 790 tavor_kstat_perfcntr64_thread_create(state);
796 791 }
797 792
798 793 } else if (ksi64->tki64_enabled) {
799 794 /* Disable 64 bit software counters */
800 795 ksi64->tki64_enabled = 0;
801 796 thr_exit = 1;
802 797 for (i = 0; i < state->ts_cfg_profile->cp_num_ports;
803 798 i++) {
804 799 if (ksi->tki_perfcntr64[i].tki64_enabled) {
805 800 thr_exit = 0;
806 801 break;
807 802 }
808 803 }
809 804 if (thr_exit)
810 805 tavor_kstat_perfcntr64_thread_exit(ksi);
811 806 }
812 807 } else if (ksi64->tki64_enabled) {
813 808 /*
814 809 * Read the counters and update kstats.
815 810 */
816 811 if (tavor_kstat_perfcntr64_read(state, ksi64->tki64_port_num,
817 812 0) != TAVOR_CMD_SUCCESS) {
818 813 mutex_exit(&ksi->tki_perfcntr64_lock);
819 814 return (EIO);
820 815 }
821 816
822 817 data[TAVOR_PERFCNTR64_ENABLE_IDX].value.ui32 = 1;
823 818
824 819 data[TAVOR_PERFCNTR64_XMIT_DATA_IDX].value.ui64 =
825 820 ksi64->tki64_counters[TAVOR_PERFCNTR64_XMIT_DATA_IDX] +
826 821 ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_DATA_IDX];
827 822
828 823 data[TAVOR_PERFCNTR64_RECV_DATA_IDX].value.ui64 =
829 824 ksi64->tki64_counters[TAVOR_PERFCNTR64_RECV_DATA_IDX] +
830 825 ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_DATA_IDX];
831 826
832 827 data[TAVOR_PERFCNTR64_XMIT_PKTS_IDX].value.ui64 =
833 828 ksi64->tki64_counters[TAVOR_PERFCNTR64_XMIT_PKTS_IDX] +
834 829 ksi64->tki64_last_read[TAVOR_PERFCNTR64_XMIT_PKTS_IDX];
835 830
836 831 data[TAVOR_PERFCNTR64_RECV_PKTS_IDX].value.ui64 =
837 832 ksi64->tki64_counters[TAVOR_PERFCNTR64_RECV_PKTS_IDX] +
838 833 ksi64->tki64_last_read[TAVOR_PERFCNTR64_RECV_PKTS_IDX];
839 834
840 835 } else {
841 836 /* return 0 in kstats if not enabled */
842 837 data[TAVOR_PERFCNTR64_ENABLE_IDX].value.ui32 = 0;
843 838 for (i = 1; i < TAVOR_PERFCNTR64_NUM_COUNTERS; i++)
844 839 data[i].value.ui64 = 0;
845 840 }
846 841
847 842 mutex_exit(&ksi->tki_perfcntr64_lock);
848 843 return (0);
849 844 }
↓ open down ↓ |
436 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX