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 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/mdb_modapi.h>
27 #include <mdb/mdb_ks.h>
28 #include <sys/async.h> /* ecc_flt for pci_ecc.h */
29 #include <sys/ddi_subrdefs.h>
30 #include <sys/pci/pci_obj.h>
31 #include "niumx_var.h"
32 #include "px_obj.h"
33
34 static int intr_pci_walk_step(mdb_walk_state_t *);
35 static int intr_px_walk_step(mdb_walk_state_t *);
36 static int intr_niumx_walk_step(mdb_walk_state_t *);
37 static void intr_pci_print_items(mdb_walk_state_t *);
38 static void intr_px_print_items(mdb_walk_state_t *);
39 static char *intr_get_intr_type(uint16_t type);
40 static void intr_print_banner(void);
41
42 typedef struct intr_info {
43 uint32_t cpuid;
44 uint32_t inum;
45 uint32_t num;
46 uint32_t pil;
47 uint16_t intr_type;
48 uint16_t mondo;
49 uint8_t ino_ino;
50 uint_t intr_state;
51 int instance;
52 int shared;
53 char driver_name[12];
54 char pathname[MAXNAMELEN];
55 }
56 intr_info_t;
57
58 #define PX_MAX_ENTRIES 32
59
60 static void intr_print_elements(intr_info_t);
61 static int detailed = 0; /* Print detailed view */
62
63
64 static int
intr_walk_init(mdb_walk_state_t * wsp)65 intr_walk_init(mdb_walk_state_t *wsp)
66 {
67 wsp->walk_addr = NULL;
68
69 return (WALK_NEXT);
70 }
71
72 static int
intr_walk_step(mdb_walk_state_t * wsp)73 intr_walk_step(mdb_walk_state_t *wsp)
74 {
75 pci_t *pci_per_p;
76 px_t *px_state_p;
77 niumx_devstate_t *niumx_state_p;
78
79 /* read globally declared structures in the pci driver */
80 if (mdb_readvar(&pci_per_p, "per_pci_state") != -1) {
81 wsp->walk_addr = (uintptr_t)pci_per_p;
82 intr_pci_walk_step(wsp);
83 }
84
85 /* read globally declared structures in the px driver */
86 if (mdb_readvar(&px_state_p, "px_state_p") != -1) {
87 wsp->walk_addr = (uintptr_t)px_state_p;
88 intr_px_walk_step(wsp);
89 }
90
91 /* read globally declared structures in the niumx driver */
92 if (mdb_readvar(&niumx_state_p, "niumx_state") != -1) {
93 wsp->walk_addr = (uintptr_t)niumx_state_p;
94 intr_niumx_walk_step(wsp);
95 }
96
97 return (WALK_DONE);
98 }
99
100 static int
intr_pci_walk_step(mdb_walk_state_t * wsp)101 intr_pci_walk_step(mdb_walk_state_t *wsp)
102 {
103 pci_t *pci_per_p;
104 pci_t pci_per;
105 uintptr_t start_addr;
106
107 /* Read start of state structure array */
108 if (mdb_vread(&pci_per_p, sizeof (uintptr_t),
109 (uintptr_t)wsp->walk_addr) == -1) {
110 mdb_warn("intr: failed to read the initial pci_per_p "
111 "structure\n");
112 return (WALK_ERR);
113 }
114
115 /* Figure out how many items are here */
116 start_addr = (uintptr_t)pci_per_p;
117
118 intr_print_banner();
119
120 while (mdb_vread(&pci_per_p, sizeof (uintptr_t),
121 (uintptr_t)start_addr) != -1) {
122 /* Read until nothing is left */
123 if (mdb_vread(&pci_per, sizeof (pci_t),
124 (uintptr_t)pci_per_p) == -1) {
125 return (WALK_DONE);
126 }
127
128 wsp->walk_addr = (uintptr_t)pci_per.pci_ib_p;
129 intr_pci_print_items(wsp);
130
131 start_addr += sizeof (uintptr_t);
132 }
133
134 return (WALK_DONE);
135 }
136
137 static int
intr_px_walk_step(mdb_walk_state_t * wsp)138 intr_px_walk_step(mdb_walk_state_t *wsp)
139 {
140 px_t *px_state_p;
141 px_t px_state;
142 uintptr_t start_addr;
143 int x;
144
145 /* Read start of state structure array */
146 if (mdb_vread(&px_state_p, sizeof (uintptr_t),
147 (uintptr_t)wsp->walk_addr) == -1) {
148 mdb_warn("intr: failed to read the initial px_per_p "
149 "structure\n");
150 return (WALK_ERR);
151 }
152
153 /* Figure out how many items are here */
154 start_addr = (uintptr_t)px_state_p;
155
156 intr_print_banner();
157
158 for (x = 0; x < PX_MAX_ENTRIES; x++) {
159 (void) mdb_vread(&px_state_p, sizeof (uintptr_t),
160 (uintptr_t)start_addr);
161
162 start_addr += sizeof (uintptr_t);
163
164 /* Read if anything is there */
165 if (mdb_vread(&px_state, sizeof (px_t),
166 (uintptr_t)px_state_p) == -1) {
167 continue;
168 }
169
170 wsp->walk_addr = (uintptr_t)px_state.px_ib_p;
171 intr_px_print_items(wsp);
172 }
173
174 return (WALK_DONE);
175 }
176
177 static int
intr_niumx_walk_step(mdb_walk_state_t * wsp)178 intr_niumx_walk_step(mdb_walk_state_t *wsp)
179 {
180 niumx_devstate_t *niumx_state_p;
181 niumx_devstate_t niumx_state;
182 uintptr_t start_addr;
183 char name[MODMAXNAMELEN + 1];
184 struct dev_info dev;
185 intr_info_t info;
186 int i;
187
188 /* Read start of state structure array */
189 if (mdb_vread(&niumx_state_p, sizeof (uintptr_t),
190 (uintptr_t)wsp->walk_addr) == -1) {
191 mdb_warn("intr: failed to read the initial niumx_state_p "
192 "structure\n");
193 return (WALK_ERR);
194 }
195
196 /* Figure out how many items are here */
197 start_addr = (uintptr_t)niumx_state_p;
198
199 while (mdb_vread(&niumx_state_p, sizeof (uintptr_t),
200 (uintptr_t)start_addr) >= 0) {
201
202 start_addr += sizeof (uintptr_t);
203
204 /* Read if anything is there */
205 if (mdb_vread(&niumx_state, sizeof (niumx_devstate_t),
206 (uintptr_t)niumx_state_p) == -1) {
207 return (WALK_DONE);
208 }
209
210 for (i = 0; i < NIUMX_MAX_INTRS; i++) {
211 if (niumx_state.niumx_ihtable[i].ih_sysino == 0)
212 continue;
213
214 if (niumx_state.niumx_ihtable[i].ih_dip == 0)
215 continue;
216
217 bzero((void *)&info, sizeof (intr_info_t));
218
219 info.shared = 0;
220
221 (void) mdb_devinfo2driver(
222 (uintptr_t)niumx_state.niumx_ihtable[i].ih_dip,
223 name, sizeof (name));
224
225 (void) mdb_ddi_pathname(
226 (uintptr_t)niumx_state.niumx_ihtable[i].ih_dip,
227 info.pathname, sizeof (info.pathname));
228
229 /* Get instance */
230 if (mdb_vread(&dev, sizeof (struct dev_info),
231 (uintptr_t)niumx_state.niumx_ihtable[i].ih_dip) ==
232 -1) {
233 mdb_warn("intr: failed to read DIP "
234 "structure\n");
235
236 return (WALK_DONE);
237 }
238
239 /* Make sure the name doesn't over run */
240 (void) mdb_snprintf(info.driver_name,
241 sizeof (info.driver_name), "%s", name);
242
243 info.instance = dev.devi_instance;
244 info.inum = niumx_state.niumx_ihtable[i].ih_inum;
245 info.intr_type = DDI_INTR_TYPE_FIXED;
246 info.num = 0;
247 info.intr_state = niumx_state.niumx_ihtable[i].ih_state;
248 info.ino_ino = i;
249 info.mondo = niumx_state.niumx_ihtable[i].ih_sysino;
250 info.pil = niumx_state.niumx_ihtable[i].ih_pri;
251 info.cpuid = niumx_state.niumx_ihtable[i].ih_cpuid;
252
253 intr_print_elements(info);
254 }
255 }
256
257 return (WALK_DONE);
258 }
259
260 static void
intr_pci_print_items(mdb_walk_state_t * wsp)261 intr_pci_print_items(mdb_walk_state_t *wsp)
262 {
263 ib_t ib;
264 ib_ino_info_t ino;
265 ib_ino_pil_t ipil;
266 ih_t ih;
267 int count;
268 char name[MODMAXNAMELEN + 1];
269 struct dev_info dev;
270 intr_info_t info;
271
272 if (mdb_vread(&ib, sizeof (ib_t),
273 (uintptr_t)wsp->walk_addr) == -1) {
274 mdb_warn("intr: failed to read pci interrupt block "
275 "structure\n");
276 return;
277 }
278
279 /* Read in ib_ino_info_t structure at address */
280 if (mdb_vread(&ino, sizeof (ib_ino_info_t),
281 (uintptr_t)ib.ib_ino_lst) == -1) {
282 /* Nothing here to read from */
283 return;
284 }
285
286 do {
287 if (mdb_vread(&ipil, sizeof (ib_ino_pil_t),
288 (uintptr_t)ino.ino_ipil_p) == -1) {
289 mdb_warn("intr: failed to read pci interrupt "
290 "ib_ino_pil_t structure\n");
291 return;
292 }
293
294 do {
295 if (mdb_vread(&ih, sizeof (ih_t),
296 (uintptr_t)ipil.ipil_ih_start) == -1) {
297 mdb_warn("intr: failed to read pci interrupt "
298 "ih_t structure\n");
299 return;
300 }
301
302 count = 0;
303
304 do {
305 bzero((void *)&info, sizeof (intr_info_t));
306
307 if ((ino.ino_ipil_size > 1) ||
308 (ipil.ipil_ih_size > 1)) {
309 info.shared = 1;
310 }
311
312 (void) mdb_devinfo2driver((uintptr_t)ih.ih_dip,
313 name, sizeof (name));
314
315 (void) mdb_ddi_pathname((uintptr_t)ih.ih_dip,
316 info.pathname, sizeof (info.pathname));
317
318 /* Get instance */
319 if (mdb_vread(&dev, sizeof (struct dev_info),
320 (uintptr_t)ih.ih_dip) == -1) {
321 mdb_warn("intr: failed to read DIP "
322 "structure\n");
323 return;
324 }
325
326 /* Make sure the name doesn't over run */
327 (void) mdb_snprintf(info.driver_name,
328 sizeof (info.driver_name), "%s", name);
329
330 info.instance = dev.devi_instance;
331 info.inum = ih.ih_inum;
332 info.intr_type = DDI_INTR_TYPE_FIXED;
333 info.num = 0;
334 info.intr_state = ih.ih_intr_state;
335 info.ino_ino = ino.ino_ino;
336 info.mondo = ino.ino_mondo;
337 info.pil = ipil.ipil_pil;
338 info.cpuid = ino.ino_cpuid;
339
340 intr_print_elements(info);
341 count++;
342
343 (void) mdb_vread(&ih, sizeof (ih_t),
344 (uintptr_t)ih.ih_next);
345
346 } while (count < ipil.ipil_ih_size);
347
348 } while (mdb_vread(&ipil, sizeof (ib_ino_pil_t),
349 (uintptr_t)ipil.ipil_next_p) != -1);
350
351 } while (mdb_vread(&ino, sizeof (ib_ino_info_t),
352 (uintptr_t)ino.ino_next_p) != -1);
353 }
354
355 static void
intr_px_print_items(mdb_walk_state_t * wsp)356 intr_px_print_items(mdb_walk_state_t *wsp)
357 {
358 px_ib_t ib;
359 px_ino_t ino;
360 px_ino_pil_t ipil;
361 px_ih_t ih;
362 int count;
363 char name[MODMAXNAMELEN + 1];
364 struct dev_info dev;
365 intr_info_t info;
366 devinfo_intr_t intr_p;
367
368 if (mdb_vread(&ib, sizeof (px_ib_t), wsp->walk_addr) == -1) {
369 return;
370 }
371
372 /* Read in px_ino_t structure at address */
373 if (mdb_vread(&ino, sizeof (px_ino_t),
374 (uintptr_t)ib.ib_ino_lst) == -1) {
375 /* Nothing here to read from */
376 return;
377 }
378
379 do { /* ino_next_p loop */
380 if (mdb_vread(&ipil, sizeof (px_ino_pil_t),
381 (uintptr_t)ino.ino_ipil_p) == -1) {
382 continue;
383 }
384
385 do { /* ipil_next_p loop */
386 if (mdb_vread(&ih, sizeof (px_ih_t),
387 (uintptr_t)ipil.ipil_ih_start) == -1) {
388 continue;
389 }
390
391 count = 0;
392
393 do { /* ipil_ih_size loop */
394 bzero((void *)&info, sizeof (intr_info_t));
395
396 (void) mdb_devinfo2driver((uintptr_t)ih.ih_dip,
397 name, sizeof (name));
398
399 (void) mdb_ddi_pathname((uintptr_t)ih.ih_dip,
400 info.pathname, sizeof (info.pathname));
401
402 /* Get instance */
403 if (mdb_vread(&dev, sizeof (struct dev_info),
404 (uintptr_t)ih.ih_dip) == -1) {
405 mdb_warn("intr: failed to read DIP "
406 "structure\n");
407 return;
408 }
409
410 /* Make sure the name doesn't over run */
411 (void) mdb_snprintf(info.driver_name,
412 sizeof (info.driver_name), "%s", name);
413
414 info.instance = dev.devi_instance;
415 info.inum = ih.ih_inum;
416
417 /*
418 * Read the type used, keep PCIe messages
419 * separate.
420 */
421 (void) mdb_vread(&intr_p,
422 sizeof (devinfo_intr_t),
423 (uintptr_t)dev.devi_intr_p);
424
425 if (ih.ih_rec_type != MSG_REC) {
426 info.intr_type =
427 intr_p.devi_intr_curr_type;
428 }
429
430 if ((ino.ino_ipil_size > 1) ||
431 (ipil.ipil_ih_size > 1)) {
432 info.shared = 1;
433 }
434
435 info.num = ih.ih_msg_code;
436 info.intr_state = ih.ih_intr_state;
437 info.ino_ino = ino.ino_ino;
438 info.mondo = ino.ino_sysino;
439 info.pil = ipil.ipil_pil;
440 info.cpuid = ino.ino_cpuid;
441
442 intr_print_elements(info);
443 count++;
444
445 (void) mdb_vread(&ih, sizeof (px_ih_t),
446 (uintptr_t)ih.ih_next);
447
448 } while (count < ipil.ipil_ih_size);
449
450 } while ((ipil.ipil_next_p != NULL) &&
451 (mdb_vread(&ipil, sizeof (px_ino_pil_t),
452 (uintptr_t)ipil.ipil_next_p) != -1));
453
454 } while ((ino.ino_next_p != NULL) && (mdb_vread(&ino, sizeof (px_ino_t),
455 (uintptr_t)ino.ino_next_p) != -1));
456 }
457
458 static char *
intr_get_intr_type(uint16_t type)459 intr_get_intr_type(uint16_t type)
460 {
461 switch (type) {
462 case DDI_INTR_TYPE_FIXED:
463 return ("Fixed");
464 case DDI_INTR_TYPE_MSI:
465 return ("MSI");
466 case DDI_INTR_TYPE_MSIX:
467 return ("MSI-X");
468 default:
469 return ("PCIe");
470 }
471 }
472
473 static void
intr_print_banner(void)474 intr_print_banner(void)
475 {
476 if (!detailed) {
477 mdb_printf("\n%<u>\tDevice\t"
478 " Type\t"
479 " MSG #\t"
480 " State\t"
481 " INO\t"
482 " Mondo\t"
483 " Shared\t"
484 " Pil\t"
485 " CPU %</u>"
486 "\n");
487 }
488 }
489
490 static void
intr_print_elements(intr_info_t info)491 intr_print_elements(intr_info_t info)
492 {
493 if (!detailed) {
494 mdb_printf(" %11s#%d\t", info.driver_name, info.instance);
495 mdb_printf(" %s\t", intr_get_intr_type(info.intr_type));
496 if (info.intr_type == DDI_INTR_TYPE_FIXED) {
497 mdb_printf(" --- \t");
498 } else {
499 mdb_printf(" %4d\t", info.num);
500 }
501 mdb_printf(" %2s\t",
502 info.intr_state ? "enbl" : "disbl");
503 mdb_printf(" 0x%x\t", info.ino_ino);
504 mdb_printf(" 0x%x\t", info.mondo);
505 mdb_printf(" %5s\t",
506 info.shared ? "yes" : "no");
507 mdb_printf(" %4d\t", info.pil);
508 mdb_printf(" %3d \n", info.cpuid);
509 } else {
510 mdb_printf("\n-------------------------------------------\n");
511 mdb_printf("Device:\t\t%s\n", info.driver_name);
512 mdb_printf("Instance:\t%d\n", info.instance);
513 mdb_printf("Path:\t\t%s\n", info.pathname);
514 mdb_printf("Inum:\t\t%d\n", info.inum);
515 mdb_printf("Interrupt Type:\t%s\n",
516 intr_get_intr_type(info.intr_type));
517 if (info.intr_type == DDI_INTR_TYPE_MSI) {
518 mdb_printf("MSI Number:\t%d\n", info.num);
519 } else if (info.intr_type == DDI_INTR_TYPE_MSIX) {
520 mdb_printf("MSI-X Number:\t%d\n", info.num);
521 } else if (!info.intr_type) {
522 mdb_printf("PCIe Message #:\t%d\n", info.num);
523 }
524
525 mdb_printf("Shared Intr:\t%s\n",
526 info.shared ? "yes" : "no");
527 mdb_printf("State:\t\t%d (%s)\n", info.intr_state,
528 info.intr_state ? "Enabled" : "Disabled");
529 mdb_printf("INO:\t\t0x%x\n", info.ino_ino);
530 mdb_printf("Mondo:\t\t0x%x\n", info.mondo);
531 mdb_printf("Pil:\t\t%d\n", info.pil);
532 mdb_printf("CPU:\t\t%d\n", info.cpuid);
533 }
534 }
535
536 /*ARGSUSED*/
537 static void
intr_walk_fini(mdb_walk_state_t * wsp)538 intr_walk_fini(mdb_walk_state_t *wsp)
539 {
540 /* Nothing to do here */
541 }
542
543 /*ARGSUSED*/
544 static int
intr_intr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)545 intr_intr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
546 {
547 detailed = 0;
548
549 if (mdb_getopts(argc, argv, 'd', MDB_OPT_SETBITS, TRUE, &detailed,
550 NULL) != argc)
551 return (DCMD_USAGE);
552
553 if (!(flags & DCMD_ADDRSPEC)) {
554 if (mdb_walk_dcmd("interrupts", "interrupts", argc, argv)
555 == -1) {
556 mdb_warn("can't walk pci/px buffer entries\n");
557 return (DCMD_ERR);
558 }
559 return (DCMD_OK);
560 }
561
562 return (DCMD_OK);
563 }
564
565 /*
566 * MDB module linkage information:
567 */
568
569 static const mdb_dcmd_t dcmds[] = {
570 { "interrupts", "[-d]", "display the interrupt info registered with "
571 "the PCI/PX nexus drivers", intr_intr },
572 { NULL }
573 };
574
575 static const mdb_walker_t walkers[] = {
576 { "interrupts", "walk PCI/PX interrupt structures",
577 intr_walk_init, intr_walk_step, intr_walk_fini },
578 { NULL }
579 };
580
581 static const mdb_modinfo_t modinfo = {
582 MDB_API_VERSION, dcmds, walkers
583 };
584
585 const mdb_modinfo_t *
_mdb_init(void)586 _mdb_init(void)
587 {
588 return (&modinfo);
589 }
590