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 = (uintptr_t)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