1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/types.h>
27 #include <sys/async.h>
28 #include <sys/sunddi.h>
29 #include <sys/sunndi.h>
30 #include <sys/ddi_impldefs.h>
31 #include <sys/machsystm.h>
32 #include <sys/hypervisor_api.h>
33 #include <sys/kstat.h>
34 #if defined(NIAGARA_IMPL)
35 #include <sys/niagararegs.h>
36 #elif defined(NIAGARA2_IMPL) || defined(VFALLS_IMPL) || defined(KT_IMPL)
37 #include <sys/niagara2regs.h>
38 #endif
39
40 extern char cpu_module_name[];
41
42 /*
43 * Data structure used to build array of event-names and pcr-mask values
44 */
45 typedef struct ni_kev_mask {
46 char *event_name;
47 uint64_t pcr_mask;
48 } ni_kev_mask_t;
49
50 /*
51 * Kstat data structure for DRAM and JBUS performance counters
52 *
53 * Note that these performance counters are only 31 bits wide. Since
54 * the "busstat" command assumes a 32-bit counter, we emulate a 32-bit
55 * counter by detecting overflow on read of these performance counters
56 * and using the least significant bit of the overflow count as the
57 * most significant bit (i.e. bit# 31) of the DRAM and JBUS performance
58 * counters.
59 */
60 #define NUM_OF_PICS 2
61 #define NUM_OF_PIC_REGS 2
62
63 typedef struct ni_ksinfo {
64 uint8_t pic_no_evs; /* number of events */
65 uint8_t pic_sel_shift[NUM_OF_PICS];
66 uint8_t pic_shift[NUM_OF_PICS];
67 uint64_t pic_mask[NUM_OF_PICS];
68 kstat_t *pic_name_ksp[NUM_OF_PICS];
69 kstat_t *cntr_ksp;
70 uint32_t pic_reg[NUM_OF_PIC_REGS];
71 uint32_t pcr_reg;
72 uint32_t pic_overflow[NUM_OF_PICS]; /* overflow count */
73 uint32_t pic_last_val[NUM_OF_PICS]; /* last PIC value */
74 } ni_ksinfo_t;
75
76 static ni_ksinfo_t *ni_dram_kstats[DRAM_BANKS];
77
78 #if defined(NIAGARA_IMPL)
79 static ni_ksinfo_t *ni_jbus_kstat;
80 #endif
81
82 typedef struct ni_perf_regs {
83 uint32_t pcr_reg;
84 uint32_t pic_reg[NUM_OF_PIC_REGS];
85 } ni_perf_regs_t;
86
87 static ni_perf_regs_t dram_perf_regs[] = {
88 #if defined(NIAGARA_IMPL) || defined(NIAGARA2_IMPL)
89 {HV_DRAM_CTL0, HV_DRAM_COUNT0},
90 {HV_DRAM_CTL1, HV_DRAM_COUNT1},
91 {HV_DRAM_CTL2, HV_DRAM_COUNT2},
92 {HV_DRAM_CTL3, HV_DRAM_COUNT3},
93 #elif defined(VFALLS_IMPL) || defined(KT_IMPL)
94 {HV_DRAM_CTL0, HV_DRAM_COUNT0},
95 {HV_DRAM_CTL1, HV_DRAM_COUNT1},
96 {HV_DRAM_CTL2, HV_DRAM_COUNT2},
97 {HV_DRAM_CTL3, HV_DRAM_COUNT3},
98 {HV_DRAM_CTL4, HV_DRAM_COUNT4},
99 {HV_DRAM_CTL5, HV_DRAM_COUNT5},
100 {HV_DRAM_CTL6, HV_DRAM_COUNT6},
101 {HV_DRAM_CTL7, HV_DRAM_COUNT7}
102 #endif
103 };
104
105 #ifdef VFALLS_IMPL
106 /*
107 * Kstat data structure for Zambezi performance counters
108 * These performance counters are 64 bits wide.
109 */
110 static ni_ksinfo_t *zam_lpu_kstats[ZAMBEZI_LPU_COUNTERS];
111 static ni_ksinfo_t *zam_gpd_kstats[ZAMBEZI_GPD_COUNTERS];
112 static ni_ksinfo_t *zam_asu_kstats[ZAMBEZI_ASU_COUNTERS];
113
114 typedef struct zam_perf_regs {
115 uint32_t pcr_reg;
116 uint32_t pic_reg[NUM_OF_PICS];
117 } zam_perf_regs_t;
118
119 static zam_perf_regs_t lpu_perf_regs[] = {
120 {HV_ZAM0_LPU_A_PCR, HV_ZAM0_LPU_A_PIC0, HV_ZAM0_LPU_A_PIC1},
121 {HV_ZAM0_LPU_B_PCR, HV_ZAM0_LPU_B_PIC0, HV_ZAM0_LPU_B_PIC1},
122 {HV_ZAM0_LPU_C_PCR, HV_ZAM0_LPU_C_PIC0, HV_ZAM0_LPU_C_PIC1},
123 {HV_ZAM0_LPU_D_PCR, HV_ZAM0_LPU_D_PIC0, HV_ZAM0_LPU_D_PIC1},
124
125 {HV_ZAM1_LPU_A_PCR, HV_ZAM1_LPU_A_PIC0, HV_ZAM1_LPU_A_PIC1},
126 {HV_ZAM1_LPU_B_PCR, HV_ZAM1_LPU_B_PIC0, HV_ZAM1_LPU_B_PIC1},
127 {HV_ZAM1_LPU_C_PCR, HV_ZAM1_LPU_C_PIC0, HV_ZAM1_LPU_C_PIC1},
128 {HV_ZAM1_LPU_D_PCR, HV_ZAM1_LPU_D_PIC0, HV_ZAM1_LPU_D_PIC1},
129
130 {HV_ZAM2_LPU_A_PCR, HV_ZAM2_LPU_A_PIC0, HV_ZAM2_LPU_A_PIC1},
131 {HV_ZAM2_LPU_B_PCR, HV_ZAM2_LPU_B_PIC0, HV_ZAM2_LPU_B_PIC1},
132 {HV_ZAM2_LPU_C_PCR, HV_ZAM2_LPU_C_PIC0, HV_ZAM2_LPU_C_PIC1},
133 {HV_ZAM2_LPU_D_PCR, HV_ZAM2_LPU_D_PIC0, HV_ZAM2_LPU_D_PIC1},
134
135 {HV_ZAM3_LPU_A_PCR, HV_ZAM3_LPU_A_PIC0, HV_ZAM3_LPU_A_PIC1},
136 {HV_ZAM3_LPU_B_PCR, HV_ZAM3_LPU_B_PIC0, HV_ZAM3_LPU_B_PIC1},
137 {HV_ZAM3_LPU_C_PCR, HV_ZAM3_LPU_C_PIC0, HV_ZAM3_LPU_C_PIC1},
138 {HV_ZAM3_LPU_D_PCR, HV_ZAM3_LPU_D_PIC0, HV_ZAM3_LPU_D_PIC1}
139 };
140
141 static zam_perf_regs_t gpd_perf_regs[] = {
142 {HV_ZAM0_GPD_PCR, HV_ZAM0_GPD_PIC0, HV_ZAM0_GPD_PIC1},
143 {HV_ZAM1_GPD_PCR, HV_ZAM1_GPD_PIC0, HV_ZAM1_GPD_PIC1},
144 {HV_ZAM2_GPD_PCR, HV_ZAM2_GPD_PIC0, HV_ZAM2_GPD_PIC1},
145 {HV_ZAM3_GPD_PCR, HV_ZAM3_GPD_PIC0, HV_ZAM3_GPD_PIC1}
146 };
147
148 static zam_perf_regs_t asu_perf_regs[] = {
149 {HV_ZAM0_ASU_PCR, HV_ZAM0_ASU_PIC0, HV_ZAM0_ASU_PIC1},
150 {HV_ZAM1_ASU_PCR, HV_ZAM1_ASU_PIC0, HV_ZAM1_ASU_PIC1},
151 {HV_ZAM2_ASU_PCR, HV_ZAM2_ASU_PIC0, HV_ZAM2_ASU_PIC1},
152 {HV_ZAM3_ASU_PCR, HV_ZAM3_ASU_PIC0, HV_ZAM3_ASU_PIC1}
153 };
154
155 static int zam_cntr_kstat_update(kstat_t *, int);
156 #endif
157
158 static void ni_create_name_kstat(char *, ni_ksinfo_t *, ni_kev_mask_t *);
159 static void ni_delete_name_kstat(ni_ksinfo_t *);
160
161 static kstat_t *ni_create_cntr_kstat(char *, int,
162 int (*update)(kstat_t *, int), void *);
163
164 static int ni_cntr_kstat_update(kstat_t *, int);
165
166 static kstat_t *ni_create_picN_kstat(char *, int, int, int,
167 ni_kev_mask_t *);
168
169 #ifdef DEBUG
170 static int ni_perf_debug;
171 #endif
172
173 /*
174 * Niagara, Niagara2 and VFalls DRAM Performance Events
175 */
176 static ni_kev_mask_t
177 niagara_dram_events[] = {
178 #if defined(NIAGARA_IMPL) || defined(NIAGARA2_IMPL) || defined(VFALLS_IMPL)
179 {"mem_reads", 0x0},
180 {"mem_writes", 0x1},
181 {"mem_read_write", 0x2},
182 #elif defined(KT_IMPL)
183 {"remote_reads", 0x0},
184 {"remote_writes", 0x1},
185 {"remote_read_write", 0x2},
186 #endif
187 #if defined(NIAGARA_IMPL) || defined(KT_IMPL)
188 {"bank_busy_stalls", 0x3},
189 #endif
190 {"rd_queue_latency", 0x4},
191 {"wr_queue_latency", 0x5},
192 {"rw_queue_latency", 0x6},
193 #if defined(NIAGARA_IMPL) || defined(NIAGARA2_IMPL) || defined(VFALLS_IMPL)
194 {"wb_buf_hits", 0x7},
195 #elif defined(KT_IMPL)
196 {"write_queue_drain", 0x7},
197 {"read_all_channels", 0x8},
198 {"write_starved", 0x9},
199 {"write_all_channels", 0xa},
200 {"read_write_channel0", 0xb},
201 {"read_write_channel1", 0xc},
202 #endif
203 {"clear_pic", 0xf}
204 };
205
206 #if defined(VFALLS_IMPL)
207 /*
208 * Zambezi Performance Events
209 */
210 static ni_kev_mask_t
211 zam_lpu_perf_events[] = {
212 {"none", 0x0},
213 {"clock_cycles", 0x1},
214 {"cycles_c2c_portX", 0x2},
215 {"cycles_mem_portX", 0x3},
216 {"cycles_WB_portX", 0x4},
217 {"cycles_NC_portX", 0x5},
218 {"cycles_c2c_portY", 0x6},
219 {"cycles_mem_portY", 0x7},
220 {"cycles_WB_portY", 0x8},
221 {"cycles_NC_portY", 0x9},
222 {"cycles_c2c_portZ", 0xa},
223 {"cycles_mem_portZ", 0xb},
224 {"cycles_WB_portZ", 0xc},
225 {"cycles_NC_portZ", 0xd},
226 {"cycles_TID_WB", 0xe},
227 {"cycles_TID_INV", 0xf},
228 {"cycles_TID_RTD", 0x10},
229 {"cycles_TID_RTO", 0x11},
230 {"cycles_TID_RTS", 0x12},
231 {"cycles_IO_WRM", 0x13},
232 {"cycles_IO_RD", 0x14},
233 {"cycles_WB_egress", 0x15},
234 {"cycles_INV_egress", 0x16},
235 {"cycles_RTO_egress", 0x17},
236 {"cycles_RTD_egress", 0x18},
237 {"cycles_RTS_egress", 0x19},
238 {"cycles_no_WB", 0x1a},
239 {"cycles_no_read/inv", 0x1b},
240 {"cycles_HIT_M", 0x1c},
241 {"cycles_HIT_O", 0x1d},
242 {"cycles_HIT_S", 0x1e},
243 {"cycles_WB_HIT", 0x1f},
244 {"cycles_MISS", 0x20},
245 {"cycles_READ_or_INV", 0x21},
246 {"cycles_WB", 0x22},
247 {"cycles_NDR", 0x23},
248 {"cycles_cache_miss", 0x24},
249 {"cycles_cache_hit", 0x25},
250 {"cycles_CRC_errors", 0x26},
251 {"cycles_replys_sent", 0x27},
252 {"cycles_replys_recev", 0x28},
253 {"cycles_link_retrain", 0x29},
254 {"clear_pic", 0xff}
255 };
256
257 static ni_kev_mask_t
258 zam_gpd_perf_events[] = {
259 {"none", 0x0},
260 {"clock_cycles", 0x1},
261 {"clear_pic", 0xf}
262 };
263
264 static ni_kev_mask_t
265 zam_asu_perf_events[] = {
266 {"none", 0x0},
267 {"clock_cycles", 0x1},
268 {"asu_in_pck", 0x2},
269 {"asu_out_pck", 0x3},
270 {"asu_CAM_hit", 0x4},
271 {"asu_wakeup", 0x5},
272 {"clear_pic", 0xf}
273 };
274 #endif
275
276 #if defined(NIAGARA_IMPL)
277 /*
278 * Niagara JBUS Performance Events
279 */
280 static ni_kev_mask_t
281 niagara_jbus_events[] = {
282 {"jbus_cycles", 0x1},
283 {"dma_reads", 0x2},
284 {"dma_read_latency", 0x3},
285 {"dma_writes", 0x4},
286 {"dma_write8", 0x5},
287 {"ordering_waits", 0x6},
288 {"pio_reads", 0x8},
289 {"pio_read_latency", 0x9},
290 {"aok_dok_off_cycles", 0xc},
291 {"aok_off_cycles", 0xd},
292 {"dok_off_cycles", 0xe},
293 {"clear_pic", 0xf}
294 };
295 #endif
296
297 /*
298 * Create the picN kstats for DRAM, JBUS and Zambezi events
299 */
300 void
niagara_kstat_init()301 niagara_kstat_init()
302 {
303 int i;
304 ni_ksinfo_t *ksinfop;
305 #if defined(VFALLS_IMPL) || defined(KT_IMPL)
306 uint64_t stat, pcr;
307 #endif
308
309 #ifdef DEBUG
310 if (ni_perf_debug)
311 printf("ni_kstat_init called\n");
312 #endif
313
314 /*
315 * Create DRAM perf events kstat
316 */
317 for (i = 0; i < DRAM_BANKS; i++) {
318 #if defined(VFALLS_IMPL) || defined(KT_IMPL)
319 /* check if this dram instance is enabled in the HW */
320 stat = hv_niagara_getperf(dram_perf_regs[i].pcr_reg, &pcr);
321 if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
322 #endif
323 ksinfop = (ni_ksinfo_t *)kmem_zalloc(
324 sizeof (ni_ksinfo_t), KM_NOSLEEP);
325
326 if (ksinfop == NULL) {
327 cmn_err(CE_WARN,
328 "%s: no space for dram kstat\n",
329 cpu_module_name);
330 break;
331 }
332 ksinfop->pic_no_evs =
333 sizeof (niagara_dram_events) /
334 sizeof (ni_kev_mask_t);
335 ksinfop->pic_sel_shift[0] = DRAM_PIC0_SEL_SHIFT;
336 ksinfop->pic_shift[0] = DRAM_PIC0_SHIFT;
337 ksinfop->pic_mask[0] = DRAM_PIC0_MASK;
338 ksinfop->pic_sel_shift[1] = DRAM_PIC1_SEL_SHIFT;
339 ksinfop->pic_shift[1] = DRAM_PIC1_SHIFT;
340 ksinfop->pic_mask[1] = DRAM_PIC1_MASK;
341 ksinfop->pic_reg[0] = dram_perf_regs[i].pic_reg[0];
342 ksinfop->pcr_reg = dram_perf_regs[i].pcr_reg;
343 ni_dram_kstats[i] = ksinfop;
344
345 /* create basic pic event/mask pair (only once) */
346 if (i == 0)
347 ni_create_name_kstat("dram", ksinfop,
348 niagara_dram_events);
349
350 /* create counter kstats */
351 ni_dram_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
352 "dram", i, ni_cntr_kstat_update, ksinfop);
353 #if defined(VFALLS_IMPL) || defined(KT_IMPL)
354 }
355 #endif
356 }
357
358 #ifdef VFALLS_IMPL
359 /*
360 * Create Zambezi LPU perf events kstat
361 */
362 for (i = 0; i < ZAMBEZI_LPU_COUNTERS; i++) {
363 /* check if this Zambezi LPU instance is enabled in the HW */
364 stat = hv_niagara_getperf(lpu_perf_regs[i].pcr_reg, &pcr);
365 if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
366 ksinfop = (ni_ksinfo_t *)kmem_zalloc(
367 sizeof (ni_ksinfo_t), KM_NOSLEEP);
368
369 if (ksinfop == NULL) {
370 cmn_err(CE_WARN,
371 "%s: no space for zambezi lpu kstat\n",
372 cpu_module_name);
373 break;
374 }
375 ksinfop->pic_no_evs =
376 sizeof (zam_lpu_perf_events) /
377 sizeof (ni_kev_mask_t);
378 ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
379 ksinfop->pic_reg[0] = lpu_perf_regs[i].pic_reg[0];
380 ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
381 ksinfop->pic_reg[1] = lpu_perf_regs[i].pic_reg[1];
382 ksinfop->pcr_reg = lpu_perf_regs[i].pcr_reg;
383 zam_lpu_kstats[i] = ksinfop;
384
385 /* create basic pic event/mask pair (only once) */
386 if (i == 0)
387 ni_create_name_kstat("lpu", ksinfop,
388 zam_lpu_perf_events);
389
390 /* create counter kstats */
391 zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
392 "lpu", i, zam_cntr_kstat_update, ksinfop);
393 }
394 }
395 /*
396 * Create Zambezi GPD perf events kstat
397 */
398 for (i = 0; i < ZAMBEZI_GPD_COUNTERS; i++) {
399 /* check if this Zambezi GPD instance is enabled in the HW */
400 stat = hv_niagara_getperf(gpd_perf_regs[i].pcr_reg, &pcr);
401 if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
402 ksinfop = (ni_ksinfo_t *)kmem_zalloc(
403 sizeof (ni_ksinfo_t), KM_NOSLEEP);
404
405 if (ksinfop == NULL) {
406 cmn_err(CE_WARN,
407 "%s: no space for zambezi gpd kstat\n",
408 cpu_module_name);
409 break;
410 }
411 ksinfop->pic_no_evs =
412 sizeof (zam_gpd_perf_events) /
413 sizeof (ni_kev_mask_t);
414 ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
415 ksinfop->pic_reg[0] = gpd_perf_regs[i].pic_reg[0];
416 ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
417 ksinfop->pic_reg[1] = gpd_perf_regs[i].pic_reg[1];
418 ksinfop->pcr_reg = gpd_perf_regs[i].pcr_reg;
419 zam_gpd_kstats[i] = ksinfop;
420
421 /* create basic pic event/mask pair (only once) */
422 if (i == 0)
423 ni_create_name_kstat("gpd", ksinfop,
424 zam_gpd_perf_events);
425
426 /* create counter kstats */
427 zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
428 "gpd", i, zam_cntr_kstat_update, ksinfop);
429 }
430 }
431 /*
432 * Create Zambezi ASU perf events kstat
433 */
434 for (i = 0; i < ZAMBEZI_ASU_COUNTERS; i++) {
435 /* check if this Zambezi ASU instance is enabled in the HW */
436 stat = hv_niagara_getperf(asu_perf_regs[i].pcr_reg, &pcr);
437 if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
438 ksinfop = (ni_ksinfo_t *)kmem_zalloc(
439 sizeof (ni_ksinfo_t), KM_NOSLEEP);
440
441 if (ksinfop == NULL) {
442 cmn_err(CE_WARN,
443 "%s: no space for zambezi asu kstat\n",
444 cpu_module_name);
445 break;
446 }
447 ksinfop->pic_no_evs =
448 sizeof (zam_asu_perf_events) /
449 sizeof (ni_kev_mask_t);
450 ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
451 ksinfop->pic_reg[0] = asu_perf_regs[i].pic_reg[0];
452 ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
453 ksinfop->pic_reg[1] = asu_perf_regs[i].pic_reg[1];
454 ksinfop->pcr_reg = asu_perf_regs[i].pcr_reg;
455 zam_asu_kstats[i] = ksinfop;
456
457 /* create basic pic event/mask pair (only once) */
458 if (i == 0)
459 ni_create_name_kstat("asu", ksinfop,
460 zam_asu_perf_events);
461
462 /* create counter kstats */
463 zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
464 "asu", i, zam_cntr_kstat_update, ksinfop);
465 }
466 }
467 #endif
468
469 #if defined(NIAGARA_IMPL)
470 /*
471 * Create JBUS perf events kstat
472 */
473 ni_jbus_kstat = (ni_ksinfo_t *)kmem_alloc(sizeof (ni_ksinfo_t),
474 KM_NOSLEEP);
475
476 if (ni_jbus_kstat == NULL) {
477 cmn_err(CE_WARN, "%s: no space for niagara jbus kstat\n",
478 cpu_module_name);
479 } else {
480 ni_jbus_kstat->pic_no_evs =
481 sizeof (niagara_jbus_events) / sizeof (ni_kev_mask_t);
482 ni_jbus_kstat->pic_sel_shift[0] = NIAGARA_JBUS_PIC0_SEL_SHIFT;
483 ni_jbus_kstat->pic_shift[0] = NIAGARA_JBUS_PIC0_SHIFT;
484 ni_jbus_kstat->pic_mask[0] = NIAGARA_JBUS_PIC0_MASK;
485 ni_jbus_kstat->pic_sel_shift[1] = NIAGARA_JBUS_PIC1_SEL_SHIFT;
486 ni_jbus_kstat->pic_shift[1] = NIAGARA_JBUS_PIC1_SHIFT;
487 ni_jbus_kstat->pic_mask[1] = NIAGARA_JBUS_PIC1_MASK;
488 ni_jbus_kstat->pic_reg[0] = HV_NIAGARA_JBUS_COUNT;
489 ni_jbus_kstat->pcr_reg = HV_NIAGARA_JBUS_CTL;
490 ni_create_name_kstat("jbus", ni_jbus_kstat,
491 niagara_jbus_events);
492 ni_jbus_kstat->cntr_ksp = ni_create_cntr_kstat("jbus", 0,
493 ni_cntr_kstat_update, ni_jbus_kstat);
494 }
495 #endif
496 }
497
498 void
niagara_kstat_fini()499 niagara_kstat_fini()
500 {
501 int i;
502
503 #ifdef DEBUG
504 if (ni_perf_debug)
505 printf("ni_kstat_fini called\n");
506 #endif
507
508 for (i = 0; i < DRAM_BANKS; i++) {
509 if (ni_dram_kstats[i] != NULL) {
510 ni_delete_name_kstat(ni_dram_kstats[i]);
511 if (ni_dram_kstats[i]->cntr_ksp != NULL)
512 kstat_delete(ni_dram_kstats[i]->cntr_ksp);
513 kmem_free(ni_dram_kstats[i], sizeof (ni_ksinfo_t));
514 ni_dram_kstats[i] = NULL;
515 }
516 }
517
518 #if defined(VFALLS_IMPL)
519 for (i = 0; i < ZAMBEZI_LPU_COUNTERS; i++) {
520 if (zam_lpu_kstats[i] != NULL) {
521 ni_delete_name_kstat(zam_lpu_kstats[i]);
522 if (zam_lpu_kstats[i]->cntr_ksp != NULL)
523 kstat_delete(zam_lpu_kstats[i]->cntr_ksp);
524 kmem_free(zam_lpu_kstats[i], sizeof (ni_ksinfo_t));
525 zam_lpu_kstats[i] = NULL;
526 }
527 }
528
529 for (i = 0; i < ZAMBEZI_GPD_COUNTERS; i++) {
530 if (zam_gpd_kstats[i] != NULL) {
531 ni_delete_name_kstat(zam_gpd_kstats[i]);
532 if (zam_gpd_kstats[i]->cntr_ksp != NULL)
533 kstat_delete(zam_gpd_kstats[i]->cntr_ksp);
534 kmem_free(zam_gpd_kstats[i], sizeof (ni_ksinfo_t));
535 zam_gpd_kstats[i] = NULL;
536 }
537 }
538
539 for (i = 0; i < ZAMBEZI_ASU_COUNTERS; i++) {
540 if (zam_asu_kstats[i] != NULL) {
541 ni_delete_name_kstat(zam_asu_kstats[i]);
542 if (zam_asu_kstats[i]->cntr_ksp != NULL)
543 kstat_delete(zam_asu_kstats[i]->cntr_ksp);
544 kmem_free(zam_asu_kstats[i], sizeof (ni_ksinfo_t));
545 zam_asu_kstats[i] = NULL;
546 }
547 }
548 #endif
549
550 #if defined(NIAGARA_IMPL)
551 if (ni_jbus_kstat != NULL) {
552 ni_delete_name_kstat(ni_jbus_kstat);
553 if (ni_jbus_kstat->cntr_ksp != NULL)
554 kstat_delete(ni_jbus_kstat->cntr_ksp);
555 kmem_free(ni_jbus_kstat, sizeof (ni_ksinfo_t));
556 ni_jbus_kstat = NULL;
557 }
558 #endif
559 }
560
561 static void
ni_create_name_kstat(char * name,ni_ksinfo_t * pp,ni_kev_mask_t * ev)562 ni_create_name_kstat(char *name, ni_ksinfo_t *pp, ni_kev_mask_t *ev)
563 {
564 int i;
565
566 #ifdef DEBUG
567 if (ni_perf_debug > 1)
568 printf("ni_create_name_kstat: name: %s\n", name);
569 #endif
570 for (i = 0; i < NUM_OF_PICS; i++) {
571 pp->pic_name_ksp[i] = ni_create_picN_kstat(name,
572 i, pp->pic_sel_shift[i], pp->pic_no_evs, ev);
573
574 if (pp->pic_name_ksp[i] == NULL) {
575 cmn_err(CE_WARN, "%s: unable to create name kstat",
576 cpu_module_name);
577 }
578 }
579 }
580
581 static void
ni_delete_name_kstat(ni_ksinfo_t * pp)582 ni_delete_name_kstat(ni_ksinfo_t *pp)
583 {
584 int i;
585
586 if (pp != NULL) {
587 for (i = 0; i < NUM_OF_PICS; i++) {
588 if (pp->pic_name_ksp[i] != NULL)
589 kstat_delete(pp->pic_name_ksp[i]);
590 }
591 }
592 }
593
594 /*
595 * Create the picN kstat. Returns a pointer to the
596 * kstat which the driver must store to allow it
597 * to be deleted when necessary.
598 */
599 static kstat_t *
ni_create_picN_kstat(char * mod_name,int pic,int pic_sel_shift,int num_ev,ni_kev_mask_t * ev_array)600 ni_create_picN_kstat(char *mod_name, int pic, int pic_sel_shift,
601 int num_ev, ni_kev_mask_t *ev_array)
602 {
603 struct kstat_named *pic_named_data;
604 int inst = 0;
605 int event;
606 char pic_name[30];
607 kstat_t *picN_ksp = NULL;
608
609 (void) sprintf(pic_name, "pic%d", pic);
610 if ((picN_ksp = kstat_create(mod_name, inst, pic_name,
611 "bus", KSTAT_TYPE_NAMED, num_ev, 0)) == NULL) {
612 cmn_err(CE_WARN, "%s %s : kstat create failed",
613 mod_name, pic_name);
614
615 /*
616 * It is up to the calling function to delete any kstats
617 * that may have been created already. We just
618 * return NULL to indicate an error has occured.
619 */
620 return (NULL);
621 }
622
623 pic_named_data = (struct kstat_named *)
624 picN_ksp->ks_data;
625
626 /*
627 * Write event names and their associated pcr masks. The
628 * last entry in the array (clear_pic) is added seperately
629 * below as the pic value must be inverted.
630 */
631 for (event = 0; event < num_ev - 1; event++) {
632 pic_named_data[event].value.ui64 =
633 (ev_array[event].pcr_mask << pic_sel_shift);
634
635 kstat_named_init(&pic_named_data[event],
636 ev_array[event].event_name,
637 KSTAT_DATA_UINT64);
638 }
639
640 /*
641 * add the clear_pic entry.
642 */
643 pic_named_data[event].value.ui64 =
644 (uint64_t)~(ev_array[event].pcr_mask << pic_sel_shift);
645
646 kstat_named_init(&pic_named_data[event], ev_array[event].event_name,
647 KSTAT_DATA_UINT64);
648
649 kstat_install(picN_ksp);
650
651 return (picN_ksp);
652 }
653
654 /*
655 * Create the "counters" kstat.
656 */
657 static kstat_t *
ni_create_cntr_kstat(char * name,int instance,int (* update)(kstat_t *,int),void * ksinfop)658 ni_create_cntr_kstat(char *name, int instance, int (*update)(kstat_t *, int),
659 void *ksinfop)
660 {
661 struct kstat *counters_ksp;
662 struct kstat_named *counters_named_data;
663 char pic_str[10];
664 int i;
665 int num_pics = NUM_OF_PICS;
666
667 #ifdef DEBUG
668 if (ni_perf_debug > 1)
669 printf("ni_create_cntr_kstat: name: %s instance: %d\n",
670 name, instance);
671 #endif
672
673 /*
674 * Size of kstat is num_pics + 1 as it
675 * also contains the %pcr
676 */
677 if ((counters_ksp = kstat_create(name, instance, "counters", "bus",
678 KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) {
679 cmn_err(CE_WARN,
680 "%s: kstat_create for %s%d failed", cpu_module_name,
681 name, instance);
682 return (NULL);
683 }
684
685 counters_named_data = (struct kstat_named *)(counters_ksp->ks_data);
686
687 /*
688 * Iinitialize the named kstats
689 */
690 kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64);
691
692 for (i = 0; i < num_pics; i++) {
693 (void) sprintf(pic_str, "pic%d", i);
694
695 kstat_named_init(&counters_named_data[i+1], pic_str,
696 KSTAT_DATA_UINT64);
697 }
698
699 /*
700 * Store the register offset's in the kstat's
701 * private field so that they are available
702 * to the update function.
703 */
704 counters_ksp->ks_private = (void *)ksinfop;
705 counters_ksp->ks_update = update;
706
707 kstat_install(counters_ksp);
708
709 return (counters_ksp);
710 }
711
712 #if defined(VFALLS_IMPL)
713 /*
714 * zambezi kstat update function. Handles reads/writes
715 * from/to kstat.
716 */
717 static int
zam_cntr_kstat_update(kstat_t * ksp,int rw)718 zam_cntr_kstat_update(kstat_t *ksp, int rw)
719 {
720 struct kstat_named *data_p;
721 ni_ksinfo_t *ksinfop = ksp->ks_private;
722 uint64_t pic0, pic1, pcr;
723 int stat = 0;
724 uint64_t pic0_stat = 0, pic1_stat = 0, pcr_stat = 0;
725
726 data_p = (struct kstat_named *)ksp->ks_data;
727
728 if (rw == KSTAT_WRITE) {
729 #ifdef DEBUG
730 if (ni_perf_debug)
731 printf("zam_cntr_kstat_update: wr pcr-%d: %lx\n",
732 ksinfop->pcr_reg, data_p[0].value.ui64);
733 #endif
734 if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64))
735 stat = EACCES;
736 } else {
737 do {
738 pic0_stat = hv_niagara_getperf(ksinfop->pic_reg[0],
739 &pic0);
740 } while (pic0_stat == H_EWOULDBLOCK);
741 do {
742 pic1_stat = hv_niagara_getperf(ksinfop->pic_reg[1],
743 &pic1);
744 } while (pic1_stat == H_EWOULDBLOCK);
745 do {
746 pcr_stat = hv_niagara_getperf(ksinfop->pcr_reg,
747 &pcr);
748 } while (pcr_stat == H_EWOULDBLOCK);
749 if (pic0_stat != 0 || pic1_stat != 0 || pcr_stat != 0)
750 stat = EACCES;
751 else {
752 data_p[0].value.ui64 = pcr;
753 data_p[1].value.ui64 = pic0;
754 data_p[2].value.ui64 = pic1;
755 }
756 #ifdef DEBUG
757 if (ni_perf_debug)
758 printf("zam_cntr_kstat_update: rd pcr%d: %lx "
759 "pic0: %16lx pic1: %16lx\n",
760 ksinfop->pcr_reg, pcr,
761 data_p[1].value.ui64, data_p[2].value.ui64);
762 #endif
763 }
764
765 return (stat);
766 }
767 #endif
768
769 /*
770 * kstat update function. Handles reads/writes
771 * from/to kstat.
772 */
773 static int
ni_cntr_kstat_update(kstat_t * ksp,int rw)774 ni_cntr_kstat_update(kstat_t *ksp, int rw)
775 {
776 struct kstat_named *data_p;
777 ni_ksinfo_t *ksinfop = ksp->ks_private;
778 uint64_t pic, pcr;
779 int stat = 0;
780 uint32_t pic0, pic1;
781
782 data_p = (struct kstat_named *)ksp->ks_data;
783
784 if (rw == KSTAT_WRITE) {
785 #ifdef DEBUG
786 if (ni_perf_debug)
787 printf("ni_cntr_kstat_update: wr pcr-%d: %lx\n",
788 ksinfop->pcr_reg, data_p[0].value.ui64);
789 #endif
790 if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64))
791 stat = EACCES;
792 } else {
793 if (hv_niagara_getperf(ksinfop->pic_reg[0], &pic) != 0 ||
794 hv_niagara_getperf(ksinfop->pcr_reg, &pcr) != 0)
795 stat = EACCES;
796 else {
797 data_p[0].value.ui64 = pcr;
798
799 /*
800 * Generate a 32-bit PIC0 value by detecting overflow
801 */
802 pic0 = (uint32_t)((pic >> ksinfop->pic_shift[0]) &
803 ksinfop->pic_mask[0]);
804 if (pic0 < ksinfop->pic_last_val[0])
805 ksinfop->pic_overflow[0]++;
806 ksinfop->pic_last_val[0] = pic0;
807 pic0 += (ksinfop->pic_overflow[0] & 1) << 31;
808 data_p[1].value.ui64 = (uint64_t)pic0;
809
810 /*
811 * Generate a 32-bit PIC1 value by detecting overflow
812 */
813 pic1 = (uint32_t)((pic >> ksinfop->pic_shift[1]) &
814 ksinfop->pic_mask[1]);
815 if (pic1 < ksinfop->pic_last_val[1])
816 ksinfop->pic_overflow[1]++;
817 ksinfop->pic_last_val[1] = pic1;
818 pic1 += (ksinfop->pic_overflow[1] & 1) << 31;
819 data_p[2].value.ui64 = (uint64_t)pic1;
820 }
821 #ifdef DEBUG
822 if (ni_perf_debug)
823 printf("ni_cntr_kstat_update: rd pcr%d: %lx "
824 "pic%d: %16lx pic0: %8lx pic1: %8lx\n",
825 ksinfop->pcr_reg, pcr, ksinfop->pic_reg[0], pic,
826 data_p[1].value.ui64, data_p[2].value.ui64);
827 #endif
828 }
829 return (stat);
830 }
831