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